about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-13 15:01:50 +0000
committerbors <bors@rust-lang.org>2024-08-13 15:01:50 +0000
commitf96e296927cc0c6e9dd611edb943f6349001eca5 (patch)
tree76c5e72c0570998ece04f11ac90e09b5d2613abc /compiler
parent00423bb1d85f3513e534abdb26f54a6966e88d47 (diff)
parent28af7e09581c3b39cdbf2850df2f157690ab7e56 (diff)
downloadrust-f96e296927cc0c6e9dd611edb943f6349001eca5.tar.gz
rust-f96e296927cc0c6e9dd611edb943f6349001eca5.zip
Auto merge of #17880 - lnicola:sync-from-rust, r=lnicola
minor: sync from downstream
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc/src/main.rs3
-rw-r--r--compiler/rustc_abi/src/layout.rs9
-rw-r--r--compiler/rustc_abi/src/lib.rs13
-rw-r--r--compiler/rustc_arena/src/lib.rs7
-rw-r--r--compiler/rustc_arena/src/tests.rs4
-rw-r--r--compiler/rustc_ast/src/ast.rs38
-rw-r--r--compiler/rustc_ast/src/ast_traits.rs15
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs26
-rw-r--r--compiler/rustc_ast/src/entry.rs3
-rw-r--r--compiler/rustc_ast/src/expand/mod.rs3
-rw-r--r--compiler/rustc_ast/src/format.rs5
-rw-r--r--compiler/rustc_ast/src/lib.rs4
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs15
-rw-r--r--compiler/rustc_ast/src/node_id.rs3
-rw-r--r--compiler/rustc_ast/src/ptr.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs26
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs15
-rw-r--r--compiler/rustc_ast/src/util/comments.rs3
-rw-r--r--compiler/rustc_ast/src/util/comments/tests.rs3
-rw-r--r--compiler/rustc_ast/src/util/literal.rs8
-rw-r--r--compiler/rustc_ast/src/util/parser.rs3
-rw-r--r--compiler/rustc_ast/src/visit.rs9
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl12
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs43
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs20
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs30
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs16
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs12
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs13
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs16
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs21
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs47
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs8
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs7
-rw-r--r--compiler/rustc_ast_pretty/src/helpers.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs6
-rw-r--r--compiler/rustc_ast_pretty/src/pp/convenience.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/mod.rs5
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs27
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs16
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs12
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/tests.rs7
-rw-r--r--compiler/rustc_attr/messages.ftl3
-rw-r--r--compiler/rustc_attr/src/builtin.rs33
-rw-r--r--compiler/rustc_attr/src/lib.rs6
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs7
-rw-r--r--compiler/rustc_borrowck/messages.ftl21
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs15
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/constraints/graph.rs7
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs12
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs22
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs11
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs28
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs129
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs16
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_use.rs7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs23
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs19
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs17
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs10
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs83
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs3
-rw-r--r--compiler/rustc_borrowck/src/facts.rs17
-rw-r--r--compiler/rustc_borrowck/src/lib.rs54
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs5
-rw-r--r--compiler/rustc_borrowck/src/nll.rs38
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs10
-rw-r--r--compiler/rustc_borrowck/src/place_ext.rs6
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs10
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs16
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_kills.rs5
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/dump_mir.rs8
-rw-r--r--compiler/rustc_borrowck/src/region_infer/graphviz.rs3
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs26
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs49
-rw-r--r--compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs8
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs11
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs6
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs50
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs13
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs11
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs21
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs54
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs10
-rw-r--r--compiler/rustc_borrowck/src/util/collect_writes.rs3
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl6
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs57
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_accessible.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/cmdline_attrs.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/compile_error.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs76
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs248
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs20
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/pattern_type.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/trace_macros.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml13
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/audit.yml1
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml1
-rw-r--r--compiler/rustc_codegen_cranelift/.zed/settings.json68
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock66
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml12
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md1
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs31
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/config.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/main.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/utils.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt1
-rw-r--r--compiler/rustc_codegen_cranelift/example/alloc_system.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/example/raw-dylib.rs31
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch32
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch75
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch6
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch14
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch25
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch47
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch37
-rw-r--r--compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml455
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain3
-rw-r--r--compiler/rustc_codegen_cranelift/rustfmt.toml2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh8
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs84
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs27
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/compiler_builtins.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs144
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs23
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/optimize/peephole.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs6
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock2
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml4
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/build.rs18
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/clean.rs4
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs4
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/config.rs15
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/fmt.rs3
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/main.rs3
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/prepare.rs6
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/rust_tools.rs8
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/test.rs18
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs11
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs11
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/int.rs19
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs11
-rw-r--r--compiler/rustc_codegen_gcc/src/mono_item.rs3
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl10
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs109
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs44
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs187
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs33
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/back/profiling.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs55
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs80
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs90
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs47
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs63
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs46
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs52
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs45
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs27
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs45
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs60
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs20
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs34
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs321
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs21
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/value.rs8
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml6
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl16
-rw-r--r--compiler/rustc_codegen_ssa/src/assert_module_sources.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs187
-rw-r--r--compiler/rustc_codegen_ssa/src/back/command.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs258
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/lto.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath/tests.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs42
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs45
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs85
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/mod.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs43
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs31
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/locals.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs41
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs27
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/size_of_val.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/asm.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs27
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/debuginfo.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/declare.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/intrinsic.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/misc.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/mod.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/statics.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs6
-rw-r--r--compiler/rustc_const_eval/messages.ftl61
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs21
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs6
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs11
-rw-r--r--compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs3
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs3
-rw-r--r--compiler/rustc_const_eval/src/check_consts/resolver.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/dummy_machine.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs12
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs21
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs41
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs10
-rw-r--r--compiler/rustc_const_eval/src/errors.rs67
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs (renamed from compiler/rustc_const_eval/src/interpret/terminator.rs)841
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs787
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs122
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs43
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs114
-rw-r--r--compiler/rustc_const_eval/src/interpret/mod.rs22
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs69
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs43
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs651
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs294
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs198
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs7
-rw-r--r--compiler/rustc_const_eval/src/lib.rs4
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs3
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs12
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs10
-rw-r--r--compiler/rustc_data_structures/src/base_n.rs3
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs9
-rw-r--r--compiler/rustc_data_structures/src/flat_map_in_place.rs3
-rw-r--r--compiler/rustc_data_structures/src/flock/unix.rs3
-rw-r--r--compiler/rustc_data_structures/src/flock/windows.rs14
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs5
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/tests.rs3
-rw-r--r--compiler/rustc_data_structures/src/graph/implementation/mod.rs3
-rw-r--r--compiler/rustc_data_structures/src/graph/implementation/tests.rs3
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/mod.rs6
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/tests.rs1
-rw-r--r--compiler/rustc_data_structures/src/graph/scc/mod.rs13
-rw-r--r--compiler/rustc_data_structures/src/graph/tests.rs2
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/mod.rs3
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/tests.rs3
-rw-r--r--compiler/rustc_data_structures/src/hashes.rs6
-rw-r--r--compiler/rustc_data_structures/src/intern.rs3
-rw-r--r--compiler/rustc_data_structures/src/jobserver.rs5
-rw-r--r--compiler/rustc_data_structures/src/lib.rs10
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/graphviz.rs9
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/tests.rs4
-rw-r--r--compiler/rustc_data_structures/src/owned_slice.rs5
-rw-r--r--compiler/rustc_data_structures/src/owned_slice/tests.rs18
-rw-r--r--compiler/rustc_data_structures/src/packed.rs6
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs9
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs15
-rw-r--r--compiler/rustc_data_structures/src/snapshot_map/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs6
-rw-r--r--compiler/rustc_data_structures/src/sorted_map/index_map.rs3
-rw-r--r--compiler/rustc_data_structures/src/sso/map.rs8
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs15
-rw-r--r--compiler/rustc_data_structures/src/steal.rs9
-rw-r--r--compiler/rustc_data_structures/src/svh.rs6
-rw-r--r--compiler/rustc_data_structures/src/sync.rs4
-rw-r--r--compiler/rustc_data_structures/src/sync/freeze.rs15
-rw-r--r--compiler/rustc_data_structures/src/sync/lock.rs21
-rw-r--r--compiler/rustc_data_structures/src/sync/parallel.rs7
-rw-r--r--compiler/rustc_data_structures/src/sync/worker_local.rs5
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy.rs5
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop.rs3
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs3
-rw-r--r--compiler/rustc_data_structures/src/temp_dir.rs1
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs14
-rw-r--r--compiler/rustc_data_structures/src/unord.rs22
-rw-r--r--compiler/rustc_data_structures/src/work_queue.rs3
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs136
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs8
-rw-r--r--compiler/rustc_driver_impl/src/signal_handler.rs3
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0517.md19
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0795.md4
-rw-r--r--compiler/rustc_error_messages/src/lib.rs27
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs11
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs52
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs29
-rw-r--r--compiler/rustc_errors/src/emitter.rs214
-rw-r--r--compiler/rustc_errors/src/error.rs7
-rw-r--r--compiler/rustc_errors/src/json.rs41
-rw-r--r--compiler/rustc_errors/src/json/tests.rs12
-rw-r--r--compiler/rustc_errors/src/lib.rs79
-rw-r--r--compiler/rustc_errors/src/lock.rs8
-rw-r--r--compiler/rustc_errors/src/markdown/parse.rs3
-rw-r--r--compiler/rustc_errors/src/markdown/tests/parse.rs3
-rw-r--r--compiler/rustc_errors/src/markdown/tests/term.rs1
-rw-r--r--compiler/rustc_errors/src/registry.rs3
-rw-r--r--compiler/rustc_errors/src/snippet.rs3
-rw-r--r--compiler/rustc_errors/src/tests.rs8
-rw-r--r--compiler/rustc_errors/src/translation.rs12
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/base.rs33
-rw-r--r--compiler/rustc_expand/src/build.rs9
-rw-r--r--compiler/rustc_expand/src/config.rs42
-rw-r--r--compiler/rustc_expand/src/errors.rs3
-rw-r--r--compiler/rustc_expand/src/expand.rs44
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs63
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs12
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs20
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs38
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs14
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs25
-rw-r--r--compiler/rustc_expand/src/module.rs17
-rw-r--r--compiler/rustc_expand/src/placeholders.rs6
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs7
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs6
-rw-r--r--compiler/rustc_feature/src/accepted.rs13
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs17
-rw-r--r--compiler/rustc_feature/src/lib.rs8
-rw-r--r--compiler/rustc_feature/src/removed.rs8
-rw-r--r--compiler/rustc_feature/src/unstable.rs27
-rw-r--r--compiler/rustc_fluent_macro/src/fluent.rs18
-rw-r--r--compiler/rustc_fs_util/src/lib.rs3
-rw-r--r--compiler/rustc_graphviz/src/lib.rs4
-rw-r--r--compiler/rustc_graphviz/src/tests.rs6
-rw-r--r--compiler/rustc_hir/src/def.rs8
-rw-r--r--compiler/rustc_hir/src/definitions.rs12
-rw-r--r--compiler/rustc_hir/src/diagnostic_items.rs3
-rw-r--r--compiler/rustc_hir/src/hir.rs49
-rw-r--r--compiler/rustc_hir/src/hir_id.rs9
-rw-r--r--compiler/rustc_hir/src/intravisit.rs3
-rw-r--r--compiler/rustc_hir/src/lang_items.rs6
-rw-r--r--compiler/rustc_hir/src/pat_util.rs9
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs2
-rw-r--r--compiler/rustc_hir/src/target.rs5
-rw-r--r--compiler/rustc_hir/src/tests.rs3
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs4
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl3
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs42
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs71
-rw-r--r--compiler/rustc_hir_analysis/src/delegation.rs261
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs86
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs113
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs3
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/diverges.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs83
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs85
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs54
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs25
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs33
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs74
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs73
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs80
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs8
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs14
-rw-r--r--compiler/rustc_incremental/src/errors.rs6
-rw-r--r--compiler/rustc_incremental/src/lib.rs14
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs7
-rw-r--r--compiler/rustc_incremental/src/persist/file_format.rs13
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs23
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs10
-rw-r--r--compiler/rustc_incremental/src/persist/mod.rs11
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs13
-rw-r--r--compiler/rustc_incremental/src/persist/work_product.rs10
-rw-r--r--compiler/rustc_index/src/bit_set.rs11
-rw-r--r--compiler/rustc_index/src/bit_set/tests.rs1
-rw-r--r--compiler/rustc_index/src/interval.rs3
-rw-r--r--compiler/rustc_index/src/lib.rs5
-rw-r--r--compiler/rustc_index/src/slice.rs9
-rw-r--r--compiler/rustc_index/src/vec.rs10
-rw-r--r--compiler/rustc_infer/src/infer/at.rs5
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs17
-rw-r--r--compiler/rustc_infer/src/infer/canonical/instantiate.rs6
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs9
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs27
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs6
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs23
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs103
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs12
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs3
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs6
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs16
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs3
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs12
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs3
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs10
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs17
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs16
-rw-r--r--compiler/rustc_infer/src/infer/relate/higher_ranked.rs5
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs7
-rw-r--r--compiler/rustc_infer/src/infer/relate/lub.rs10
-rw-r--r--compiler/rustc_infer/src/infer/relate/mod.rs3
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs12
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs3
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/fudge.rs13
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/undo_log.rs9
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs11
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs4
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs14
-rw-r--r--compiler/rustc_infer/src/traits/project.rs14
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs7
-rw-r--r--compiler/rustc_infer/src/traits/util.rs6
-rw-r--r--compiler/rustc_interface/src/callbacks.rs3
-rw-r--r--compiler/rustc_interface/src/errors.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs20
-rw-r--r--compiler/rustc_interface/src/passes.rs44
-rw-r--r--compiler/rustc_interface/src/queries.rs13
-rw-r--r--compiler/rustc_interface/src/tests.rs40
-rw-r--r--compiler/rustc_interface/src/util.rs22
-rw-r--r--compiler/rustc_lexer/src/lib.rs4
-rw-r--r--compiler/rustc_lexer/src/tests.rs4
-rw-r--r--compiler/rustc_lint/messages.ftl16
-rw-r--r--compiler/rustc_lint/src/async_fn_in_trait.rs6
-rw-r--r--compiler/rustc_lint/src/builtin.rs79
-rw-r--r--compiler/rustc_lint/src/context.rs39
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs8
-rw-r--r--compiler/rustc_lint/src/context/diagnostics/check_cfg.rs3
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs8
-rw-r--r--compiler/rustc_lint/src/drop_forget_useless.rs10
-rw-r--r--compiler/rustc_lint/src/early.rs7
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs15
-rw-r--r--compiler/rustc_lint/src/errors.rs6
-rw-r--r--compiler/rustc_lint/src/expect.rs3
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs17
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs12
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs3
-rw-r--r--compiler/rustc_lint/src/internal.rs20
-rw-r--r--compiler/rustc_lint/src/late.rs12
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs18
-rw-r--r--compiler/rustc_lint/src/levels.rs44
-rw-r--r--compiler/rustc_lint/src/lib.rs27
-rw-r--r--compiler/rustc_lint/src/lints.rs47
-rw-r--r--compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs14
-rw-r--r--compiler/rustc_lint/src/map_unit_fn.rs12
-rw-r--r--compiler/rustc_lint/src/methods.rs10
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs4
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs14
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs11
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs17
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs19
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs12
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs6
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs5
-rw-r--r--compiler/rustc_lint/src/passes.rs4
-rw-r--r--compiler/rustc_lint/src/precedence.rs3
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs4
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs4
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs7
-rw-r--r--compiler/rustc_lint/src/shadowed_into_iter.rs5
-rw-r--r--compiler/rustc_lint/src/tests.rs3
-rw-r--r--compiler/rustc_lint/src/traits.rs7
-rw-r--r--compiler/rustc_lint/src/types.rs79
-rw-r--r--compiler/rustc_lint/src/unit_bindings.rs5
-rw-r--r--compiler/rustc_lint/src/unused.rs47
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs146
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs20
-rw-r--r--compiler/rustc_llvm/build.rs29
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp14
-rw-r--r--compiler/rustc_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_log/src/lib.rs7
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs7
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs14
-rw-r--r--compiler/rustc_macros/src/diagnostics/error.rs3
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs13
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs17
-rw-r--r--compiler/rustc_macros/src/lib.rs3
-rw-r--r--compiler/rustc_macros/src/symbols.rs6
-rw-r--r--compiler/rustc_metadata/messages.ftl9
-rw-r--r--compiler/rustc_metadata/src/creader.rs21
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs65
-rw-r--r--compiler/rustc_metadata/src/errors.rs15
-rw-r--r--compiler/rustc_metadata/src/fs.rs14
-rw-r--r--compiler/rustc_metadata/src/locator.rs18
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs20
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs19
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs17
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs4
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs9
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs15
-rw-r--r--compiler/rustc_middle/src/error.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs34
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs5
-rw-r--r--compiler/rustc_middle/src/hir/place.rs6
-rw-r--r--compiler/rustc_middle/src/hooks/mod.rs7
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_middle/src/infer/mod.rs4
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs8
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/lint.rs14
-rw-r--r--compiler/rustc_middle/src/metadata.rs4
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs14
-rw-r--r--compiler/rustc_middle/src/middle/debugger_visualizer.rs3
-rw-r--r--compiler/rustc_middle/src/middle/exported_symbols.rs4
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs4
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs10
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs3
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs6
-rw-r--r--compiler/rustc_middle/src/middle/region.rs7
-rw-r--r--compiler/rustc_middle/src/middle/resolve_bound_vars.rs4
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs7
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs6
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs9
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs4
-rw-r--r--compiler/rustc_middle/src/mir/generic_graphviz.rs3
-rw-r--r--compiler/rustc_middle/src/mir/graphviz.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs12
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs22
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs178
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs101
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs15
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs12
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs118
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs14
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/mir/query.rs9
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs26
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs3
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs12
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs8
-rw-r--r--compiler/rustc_middle/src/query/erase.rs8
-rw-r--r--compiler/rustc_middle/src/query/keys.rs13
-rw-r--r--compiler/rustc_middle/src/query/mod.rs113
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs16
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs29
-rw-r--r--compiler/rustc_middle/src/thir.rs179
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs16
-rw-r--r--compiler/rustc_middle/src/traits/query.rs14
-rw-r--r--compiler/rustc_middle/src/traits/select.rs10
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs9
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs4
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs5
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs3
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs19
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs11
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs4
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs14
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs24
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs10
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs9
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs16
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs3
-rw-r--r--compiler/rustc_middle/src/ty/context.rs81
-rw-r--r--compiler/rustc_middle/src/ty/context/tls.rs14
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs12
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs3
-rw-r--r--compiler/rustc_middle/src/ty/error.rs10
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs3
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs6
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs25
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs16
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs16
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs21
-rw-r--r--compiler/rustc_middle/src/ty/intrinsic.rs3
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs37
-rw-r--r--compiler/rustc_middle/src/ty/list.rs17
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs64
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs5
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs8
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs3
-rw-r--r--compiler/rustc_middle/src/ty/pattern.rs3
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs3
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs24
-rw-r--r--compiler/rustc_middle/src/ty/region.rs6
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs3
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs18
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs35
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs5
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs30
-rw-r--r--compiler/rustc_middle/src/ty/util.rs57
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs6
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs14
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs4
-rw-r--r--compiler/rustc_middle/src/util/bug.rs8
-rw-r--r--compiler/rustc_middle/src/util/call_kind.rs4
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs6
-rw-r--r--compiler/rustc_middle/src/values.rs17
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/cfg.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs29
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs17
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs13
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs475
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs85
-rw-r--r--compiler/rustc_mir_build/src/build/misc.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs3
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs28
-rw-r--r--compiler/rustc_mir_build/src/errors.rs14
-rw-r--r--compiler/rustc_mir_build/src/lints.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs29
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/drop_flag_effects.rs9
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs20
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/fmt.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/lattice.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs73
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs9
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/mod.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs29
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs10
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml1
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs3
-rw-r--r--compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs6
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs3
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs22
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs7
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs7
-rw-r--r--compiler/rustc_mir_transform/src/ctfe_limit.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs3
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs9
-rw-r--r--compiler/rustc_mir_transform/src/dump_mir.rs6
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs9
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs17
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs34
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs6
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs3
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs78
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs33
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs3
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs32
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs3
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs47
-rw-r--r--compiler/rustc_mir_transform/src/lint.rs3
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs3
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs149
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs6
-rw-r--r--compiler/rustc_mir_transform/src/multiple_return_terminators.rs3
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs3
-rw-r--r--compiler/rustc_mir_transform/src/prettify.rs3
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs40
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs12
-rw-r--r--compiler/rustc_mir_transform/src/required_consts.rs13
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs35
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs16
-rw-r--r--compiler/rustc_mir_transform/src/single_use_consts.rs3
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_enum_branching.rs3
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs18
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs21
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs3
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs3
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs6
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs18
-rw-r--r--compiler/rustc_monomorphize/src/util.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/resolve.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs15
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs74
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs5
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/inspect/build.rs5
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs13
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs36
-rw-r--r--compiler/rustc_parse/src/lexer/diagnostics.rs3
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs15
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs32
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs3
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs10
-rw-r--r--compiler/rustc_parse/src/lib.rs8
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs39
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs146
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs49
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs125
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs21
-rw-r--r--compiler/rustc_parse/src/parser/item.rs36
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs118
-rw-r--r--compiler/rustc_parse/src/parser/mut_visit/tests.rs3
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs18
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs34
-rw-r--r--compiler/rustc_parse/src/parser/path.rs20
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs77
-rw-r--r--compiler/rustc_parse/src/parser/tests.rs28
-rw-r--r--compiler/rustc_parse/src/parser/tokenstream/tests.rs6
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs19
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs152
-rw-r--r--compiler/rustc_parse_format/src/lib.rs6
-rw-r--r--compiler/rustc_passes/messages.ftl14
-rw-r--r--compiler/rustc_passes/src/check_attr.rs781
-rw-r--r--compiler/rustc_passes/src/check_const.rs3
-rw-r--r--compiler/rustc_passes/src/dead.rs215
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs12
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs3
-rw-r--r--compiler/rustc_passes/src/entry.rs5
-rw-r--r--compiler/rustc_passes/src/errors.rs24
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs6
-rw-r--r--compiler/rustc_passes/src/lang_items.rs11
-rw-r--r--compiler/rustc_passes/src/layout_test.rs3
-rw-r--r--compiler/rustc_passes/src/liveness.rs14
-rw-r--r--compiler/rustc_passes/src/liveness/rwu_table.rs3
-rw-r--r--compiler/rustc_passes/src/loops.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs8
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/errors.rs55
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/lints.rs7
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs3
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs191
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc/print.rs219
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs34
-rw-r--r--compiler/rustc_pattern_analysis/tests/common/mod.rs14
-rw-r--r--compiler/rustc_pattern_analysis/tests/complexity.rs4
-rw-r--r--compiler/rustc_pattern_analysis/tests/exhaustiveness.rs8
-rw-r--r--compiler/rustc_pattern_analysis/tests/intersection.rs4
-rw-r--r--compiler/rustc_privacy/src/errors.rs3
-rw-r--r--compiler/rustc_privacy/src/lib.rs29
-rw-r--r--compiler/rustc_query_impl/src/lib.rs15
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs18
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs5
-rw-r--r--compiler/rustc_query_system/src/cache.rs4
-rw-r--r--compiler/rustc_query_system/src/dep_graph/debug.rs17
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs12
-rw-r--r--compiler/rustc_query_system/src/dep_graph/edges.rs6
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs20
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs9
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs17
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs4
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs6
-rw-r--r--compiler/rustc_query_system/src/ich/mod.rs3
-rw-r--r--compiler/rustc_query_system/src/lib.rs4
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs10
-rw-r--r--compiler/rustc_query_system/src/query/config.rs14
-rw-r--r--compiler/rustc_query_system/src/query/job.rs21
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs7
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs31
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs46
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs19
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs6
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs64
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs17
-rw-r--r--compiler/rustc_resolve/src/errors.rs12
-rw-r--r--compiler/rustc_resolve/src/ident.rs92
-rw-r--r--compiler/rustc_resolve/src/imports.rs107
-rw-r--r--compiler/rustc_resolve/src/late.rs245
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs53
-rw-r--r--compiler/rustc_resolve/src/lib.rs74
-rw-r--r--compiler/rustc_resolve/src/macros.rs75
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs5
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs7
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs5
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs7
-rw-r--r--compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs3
-rw-r--r--compiler/rustc_serialize/src/leb128.rs5
-rw-r--r--compiler/rustc_serialize/src/opaque.rs7
-rw-r--r--compiler/rustc_serialize/src/serialize.rs3
-rw-r--r--compiler/rustc_serialize/tests/leb128.rs3
-rw-r--r--compiler/rustc_serialize/tests/opaque.rs5
-rw-r--r--compiler/rustc_session/src/code_stats.rs3
-rw-r--r--compiler/rustc_session/src/config.rs123
-rw-r--r--compiler/rustc_session/src/config/cfg.rs74
-rw-r--r--compiler/rustc_session/src/cstore.rs9
-rw-r--r--compiler/rustc_session/src/errors.rs8
-rw-r--r--compiler/rustc_session/src/filesearch.rs24
-rw-r--r--compiler/rustc_session/src/options.rs44
-rw-r--r--compiler/rustc_session/src/output.rs12
-rw-r--r--compiler/rustc_session/src/parse.rs34
-rw-r--r--compiler/rustc_session/src/search_paths.rs8
-rw-r--r--compiler/rustc_session/src/session.rs76
-rw-r--r--compiler/rustc_session/src/utils.rs10
-rw-r--r--compiler/rustc_session/src/version.rs8
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs14
-rw-r--r--compiler/rustc_smir/src/rustc_internal/pretty.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs10
-rw-r--r--compiler/rustc_smir/src/rustc_smir/builder.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs5
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/abi.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/error.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs3
-rw-r--r--compiler/rustc_span/src/caching_source_map_view.rs6
-rw-r--r--compiler/rustc_span/src/def_id.rs8
-rw-r--r--compiler/rustc_span/src/edit_distance.rs3
-rw-r--r--compiler/rustc_span/src/hygiene.rs18
-rw-r--r--compiler/rustc_span/src/lib.rs18
-rw-r--r--compiler/rustc_span/src/profiling.rs4
-rw-r--r--compiler/rustc_span/src/source_map.rs9
-rw-r--r--compiler/rustc_span/src/span_encoding.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs20
-rw-r--r--compiler/rustc_span/src/symbol/tests.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/errors.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/hashed.rs5
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs13
-rw-r--r--compiler/rustc_target/Cargo.toml2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs16
-rw-r--r--compiler/rustc_target/src/abi/call/nvptx64.rs3
-rw-r--r--compiler/rustc_target/src/abi/call/powerpc64.rs67
-rw-r--r--compiler/rustc_target/src/abi/call/x86_win64.rs10
-rw-r--r--compiler/rustc_target/src/abi/mod.rs9
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs8
-rw-r--r--compiler/rustc_target/src/asm/arm.rs8
-rw-r--r--compiler/rustc_target/src/asm/avr.rs6
-rw-r--r--compiler/rustc_target/src/asm/bpf.rs6
-rw-r--r--compiler/rustc_target/src/asm/csky.rs6
-rw-r--r--compiler/rustc_target/src/asm/hexagon.rs6
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs6
-rw-r--r--compiler/rustc_target/src/asm/m68k.rs6
-rw-r--r--compiler/rustc_target/src/asm/mips.rs6
-rw-r--r--compiler/rustc_target/src/asm/mod.rs10
-rw-r--r--compiler/rustc_target/src/asm/msp430.rs6
-rw-r--r--compiler/rustc_target/src/asm/nvptx.rs3
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs6
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs8
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs6
-rw-r--r--compiler/rustc_target/src/asm/spirv.rs3
-rw-r--r--compiler/rustc_target/src/asm/wasm.rs3
-rw-r--r--compiler/rustc_target/src/asm/x86.rs8
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/abi/tests.rs4
-rw-r--r--compiler/rustc_target/src/spec/base/apple/mod.rs10
-rw-r--r--compiler/rustc_target/src/spec/base/avr_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/base/linux.rs3
-rw-r--r--compiler/rustc_target/src/spec/base/linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/base/msvc.rs3
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnullvm.rs3
-rw-r--r--compiler/rustc_target/src/spec/crt_objects.rs3
-rw-r--r--compiler/rustc_target/src/spec/mod.rs41
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs4
-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.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs3
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs3
-rw-r--r--compiler/rustc_target/src/target_features.rs563
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs34
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs18
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs22
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs17
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note.rs14
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs14
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs70
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs221
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs40
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs53
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs22
-rw-r--r--compiler/rustc_trait_selection/src/errors/note_and_explain.rs8
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs14
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs60
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs44
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs89
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs11
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs3
-rw-r--r--compiler/rustc_traits/src/lib.rs3
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs5
-rw-r--r--compiler/rustc_traits/src/type_op.rs6
-rw-r--r--compiler/rustc_transmute/src/layout/dfa.rs6
-rw-r--r--compiler/rustc_transmute/src/layout/mod.rs3
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs6
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs23
-rw-r--r--compiler/rustc_transmute/src/lib.rs10
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs17
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/query_context.rs3
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/tests.rs9
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs6
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs7
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs3
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs3
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs18
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs12
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs3
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs6
-rw-r--r--compiler/rustc_ty_utils/src/sig_types.rs3
-rw-r--r--compiler/rustc_ty_utils/src/structural_match.rs3
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs6
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs24
-rw-r--r--compiler/rustc_type_ir/src/codec.rs4
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs35
-rw-r--r--compiler/rustc_type_ir/src/data_structures.rs19
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs13
-rw-r--r--compiler/rustc_type_ir/src/fold.rs5
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs3
-rw-r--r--compiler/rustc_type_ir/src/interner.rs12
-rw-r--r--compiler/rustc_type_ir/src/lib.rs5
-rw-r--r--compiler/rustc_type_ir/src/predicate_kind.rs21
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs50
-rw-r--r--compiler/rustc_type_ir/src/solve/inspect.rs10
-rw-r--r--compiler/rustc_type_ir/src/ty_info.rs7
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs95
-rw-r--r--compiler/rustc_type_ir/src/visit.rs5
-rw-r--r--compiler/rustc_type_ir_macros/src/lib.rs3
-rw-r--r--compiler/stable_mir/src/abi.rs14
-rw-r--r--compiler/stable_mir/src/crate_def.rs3
-rw-r--r--compiler/stable_mir/src/lib.rs9
-rw-r--r--compiler/stable_mir/src/mir/alloc.rs6
-rw-r--r--compiler/stable_mir/src/mir/body.rs6
-rw-r--r--compiler/stable_mir/src/mir/mono.rs8
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs11
-rw-r--r--compiler/stable_mir/src/target.rs3
-rw-r--r--compiler/stable_mir/src/ty.rs14
-rw-r--r--compiler/stable_mir/src/visitor.rs4
1165 files changed, 13834 insertions, 12633 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 29766fc9d87..e9a7397557e 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,3 +1,6 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
+#![feature(rustc_private)]
+
 // A note about jemalloc: rustc uses jemalloc when built for CI and
 // distribution. The obvious way to do this is with the `#[global_allocator]`
 // mechanism. However, for complicated reasons (see
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 197dd7f9c9e..5160b4ed0a2 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -1,9 +1,7 @@
 use std::borrow::{Borrow, Cow};
-use std::cmp;
 use std::fmt::{self, Write};
-use std::iter;
-use std::ops::Bound;
-use std::ops::Deref;
+use std::ops::{Bound, Deref};
+use std::{cmp, iter};
 
 use rustc_index::Idx;
 use tracing::debug;
@@ -982,7 +980,8 @@ fn univariant<
         if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
             #[cfg(feature = "randomize")]
             {
-                use rand::{seq::SliceRandom, SeedableRng};
+                use rand::seq::SliceRandom;
+                use rand::SeedableRng;
                 // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
                 // ordering.
                 let mut rng =
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 52ec41f643c..3dc548c4554 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -6,21 +6,20 @@
 // tidy-alphabetical-end
 
 use std::fmt;
+#[cfg(feature = "nightly")]
+use std::iter::Step;
 use std::num::{NonZeroUsize, ParseIntError};
 use std::ops::{Add, AddAssign, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
 use bitflags::bitflags;
-use rustc_index::{Idx, IndexSlice, IndexVec};
-
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::StableOrd;
+use rustc_index::{Idx, IndexSlice, IndexVec};
 #[cfg(feature = "nightly")]
 use rustc_macros::HashStable_Generic;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_Generic, Encodable_Generic};
-#[cfg(feature = "nightly")]
-use std::iter::Step;
 
 mod layout;
 #[cfg(test)]
@@ -517,7 +516,7 @@ impl Size {
     /// Truncates `value` to `self` bits and then sign-extends it to 128 bits
     /// (i.e., if it is negative, fill with 1's on the left).
     #[inline]
-    pub fn sign_extend(self, value: u128) -> u128 {
+    pub fn sign_extend(self, value: u128) -> i128 {
         let size = self.bits();
         if size == 0 {
             // Truncated until nothing is left.
@@ -527,7 +526,7 @@ impl Size {
         let shift = 128 - size;
         // Shift the unsigned value to the left, then shift back to the right as signed
         // (essentially fills with sign bit on the left).
-        (((value << shift) as i128) >> shift) as u128
+        ((value << shift) as i128) >> shift
     }
 
     /// Truncates `value` to `self` bits.
@@ -545,7 +544,7 @@ impl Size {
 
     #[inline]
     pub fn signed_int_min(&self) -> i128 {
-        self.sign_extend(1_u128 << (self.bits() - 1)) as i128
+        self.sign_extend(1_u128 << (self.bits() - 1))
     }
 
     #[inline]
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 810cb7a9f45..f5f01348e46 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -27,15 +27,14 @@
 #![feature(strict_provenance)]
 // tidy-alphabetical-end
 
-use smallvec::SmallVec;
-
 use std::alloc::Layout;
 use std::cell::{Cell, RefCell};
 use std::marker::PhantomData;
 use std::mem::{self, MaybeUninit};
 use std::ptr::{self, NonNull};
-use std::slice;
-use std::{cmp, intrinsics};
+use std::{cmp, intrinsics, slice};
+
+use smallvec::SmallVec;
 
 /// This calls the passed function while ensuring it won't be inlined into the caller.
 #[inline(never)]
diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs
index 49a070badc6..9eaa292e989 100644
--- a/compiler/rustc_arena/src/tests.rs
+++ b/compiler/rustc_arena/src/tests.rs
@@ -1,8 +1,10 @@
 extern crate test;
-use super::TypedArena;
 use std::cell::Cell;
+
 use test::Bencher;
 
+use super::TypedArena;
+
 #[allow(dead_code)]
 #[derive(Debug, Eq, PartialEq)]
 struct Point {
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 628badd6f23..a44ed828504 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -18,15 +18,9 @@
 //! - [`Attribute`]: Metadata associated with item.
 //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
 
-pub use crate::format::*;
-pub use crate::util::parser::ExprPrecedence;
-pub use rustc_span::AttrId;
-pub use GenericArgs::*;
-pub use UnsafeSource::*;
+use std::borrow::Cow;
+use std::{cmp, fmt, mem};
 
-use crate::ptr::P;
-use crate::token::{self, CommentKind, Delimiter};
-use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
 pub use rustc_ast_ir::{Movability, Mutability};
 use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -35,12 +29,17 @@ use rustc_data_structures::sync::Lrc;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+pub use rustc_span::AttrId;
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
-use std::borrow::Cow;
-use std::cmp;
-use std::fmt;
-use std::mem;
 use thin_vec::{thin_vec, ThinVec};
+pub use GenericArgs::*;
+pub use UnsafeSource::*;
+
+pub use crate::format::*;
+use crate::ptr::P;
+use crate::token::{self, CommentKind, Delimiter};
+use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
+pub use crate::util::parser::ExprPrecedence;
 
 /// A "Label" is an identifier of some point in sources,
 /// e.g. in the following code:
@@ -586,7 +585,9 @@ impl Pat {
             }
             // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
             // when `P` can be reparsed as a type `T`.
-            PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
+            PatKind::Slice(pats) if let [pat] = pats.as_slice() => {
+                pat.to_ty().map(TyKind::Slice)?
+            }
             // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
             // assuming `T0` to `Tn` are all syntactically valid as types.
             PatKind::Tuple(pats) => {
@@ -1188,8 +1189,8 @@ impl Expr {
     /// Does not ensure that the path resolves to a const param, the caller should check this.
     pub fn is_potential_trivial_const_arg(&self) -> bool {
         let this = if let ExprKind::Block(block, None) = &self.kind
-            && block.stmts.len() == 1
-            && let StmtKind::Expr(expr) = &block.stmts[0].kind
+            && let [stmt] = block.stmts.as_slice()
+            && let StmtKind::Expr(expr) = &stmt.kind
         {
             expr
         } else {
@@ -1249,7 +1250,9 @@ impl Expr {
                 expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))?
             }
 
-            ExprKind::Array(exprs) if exprs.len() == 1 => exprs[0].to_ty().map(TyKind::Slice)?,
+            ExprKind::Array(exprs) if let [expr] = exprs.as_slice() => {
+                expr.to_ty().map(TyKind::Slice)?
+            }
 
             ExprKind::Tup(exprs) => {
                 let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<ThinVec<_>>>()?;
@@ -3491,8 +3494,9 @@ pub type ForeignItem = Item<ForeignItemKind>;
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(AssocItem, 88);
     static_assert_size!(AssocItemKind, 16);
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 7754ca0a0f5..6b95fb7dd36 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -2,16 +2,17 @@
 //! typically those used in AST fragments during macro expansion.
 //! The traits are not implemented exhaustively, only when actually necessary.
 
+use std::fmt;
+use std::marker::PhantomData;
+
 use crate::ptr::P;
 use crate::token::Nonterminal;
 use crate::tokenstream::LazyAttrTokenStream;
-use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
-use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
-use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
-use crate::{AttrVec, Attribute, Stmt, StmtKind};
-
-use std::fmt;
-use std::marker::PhantomData;
+use crate::{
+    Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
+    FieldDef, ForeignItem, GenericParam, Item, NodeId, Param, Pat, PatField, Path, Stmt, StmtKind,
+    Ty, Variant, Visibility,
+};
 
 /// A utility trait to reduce boilerplate.
 /// Standard `Deref(Mut)` cannot be reused due to coherence.
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index d2c7b1c0753..94a00ab1a04 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -1,24 +1,24 @@
 //! Functions dealing with attributes and meta items.
 
+use std::iter;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+use rustc_index::bit_set::GrowableBitSet;
+use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
+use thin_vec::{thin_vec, ThinVec};
+
 use crate::ast::{
-    AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety,
+    AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DelimArgs,
+    Expr, ExprKind, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NormalAttr, Path,
+    PathSegment, Safety, DUMMY_NODE_ID,
 };
-use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
-use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
-use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter, Token};
-use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
-use crate::tokenstream::{LazyAttrTokenStream, TokenStream};
+use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree};
 use crate::util::comments;
 use crate::util::literal::escape_string_symbol;
-use rustc_index::bit_set::GrowableBitSet;
-use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::Span;
-use smallvec::{smallvec, SmallVec};
-use std::iter;
-use std::sync::atomic::{AtomicU32, Ordering};
-use thin_vec::{thin_vec, ThinVec};
 
 pub struct MarkedAttrs(GrowableBitSet<AttrId>);
 
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index dd231e286d5..60a12614f06 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -1,7 +1,8 @@
-use crate::{attr, Attribute};
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 
+use crate::{attr, Attribute};
+
 #[derive(Debug)]
 pub enum EntryPointType {
     /// This function is not an entrypoint.
diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs
index 37caadd0414..13413281bc7 100644
--- a/compiler/rustc_ast/src/expand/mod.rs
+++ b/compiler/rustc_ast/src/expand/mod.rs
@@ -1,7 +1,8 @@
 //! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`.
 
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_span::{def_id::DefId, symbol::Ident};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::Ident;
 
 use crate::MetaItem;
 
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index 49910e2283d..e72d32d9b75 100644
--- a/compiler/rustc_ast/src/format.rs
+++ b/compiler/rustc_ast/src/format.rs
@@ -1,10 +1,11 @@
-use crate::ptr::P;
-use crate::Expr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
+use crate::ptr::P;
+use crate::Expr;
+
 // Definitions:
 //
 // format_args!("hello {abc:.xyz$}!!", abc="world");
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 846a108091f..27e9f3d137f 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -43,11 +43,11 @@ pub mod token;
 pub mod tokenstream;
 pub mod visit;
 
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+
 pub use self::ast::*;
 pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens};
 
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
 /// instead of implementing everything in `rustc_middle`.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 8387e4499ae..8a66894a356 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -7,11 +7,8 @@
 //! a `MutVisitor` renaming item names in a module will miss all of those
 //! that are created by the expansion of a macro.
 
-use crate::ast::*;
-use crate::ptr::P;
-use crate::token::{self, Token};
-use crate::tokenstream::*;
-use crate::visit::{AssocCtxt, BoundKind};
+use std::ops::DerefMut;
+use std::panic;
 
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -20,10 +17,14 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use smallvec::{smallvec, Array, SmallVec};
-use std::ops::DerefMut;
-use std::panic;
 use thin_vec::ThinVec;
 
+use crate::ast::*;
+use crate::ptr::P;
+use crate::token::{self, Token};
+use crate::tokenstream::*;
+use crate::visit::{AssocCtxt, BoundKind};
+
 pub trait ExpectOne<A: Array> {
     fn expect_one(self, err: &'static str) -> A::Item;
 }
diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs
index 1cd24495309..adca1844b61 100644
--- a/compiler/rustc_ast/src/node_id.rs
+++ b/compiler/rustc_ast/src/node_id.rs
@@ -1,6 +1,7 @@
-use rustc_span::LocalExpnId;
 use std::fmt;
 
+use rustc_span::LocalExpnId;
+
 rustc_index::newtype_index! {
     /// Identifies an AST node.
     ///
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 34c539ea16b..97c714df8fd 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -21,9 +21,8 @@ use std::fmt::{self, Debug, Display};
 use std::ops::{Deref, DerefMut};
 use std::{slice, vec};
 
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 /// An owned smart pointer.
 ///
 /// See the [module level documentation][crate::ptr] for details.
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 9478da236c3..43d87b96ead 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -1,3 +1,15 @@
+use std::borrow::Cow;
+use std::fmt;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+use rustc_span::edition::Edition;
+use rustc_span::symbol::{kw, sym};
+#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint.
+#[allow(hidden_glob_reexports)]
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 pub use BinOpToken::*;
 pub use LitKind::*;
 pub use Nonterminal::*;
@@ -9,17 +21,6 @@ use crate::ast;
 use crate::ptr::P;
 use crate::util::case::Case;
 
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::Lrc;
-use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_span::symbol::{kw, sym};
-#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint.
-#[allow(hidden_glob_reexports)]
-use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::{edition::Edition, ErrorGuaranteed, Span, DUMMY_SP};
-use std::borrow::Cow;
-use std::fmt;
-
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum CommentKind {
     Line,
@@ -1062,8 +1063,9 @@ where
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Lit, 12);
     static_assert_size!(LitKind, 2);
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index a92ef575777..057b4455dca 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -13,10 +13,8 @@
 //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
-use crate::ast::{AttrStyle, StmtKind};
-use crate::ast_traits::{HasAttrs, HasTokens};
-use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
-use crate::{AttrVec, Attribute};
+use std::borrow::Cow;
+use std::{cmp, fmt, iter};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{self, Lrc};
@@ -24,8 +22,10 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP};
 
-use std::borrow::Cow;
-use std::{cmp, fmt, iter};
+use crate::ast::{AttrStyle, StmtKind};
+use crate::ast_traits::{HasAttrs, HasTokens};
+use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
+use crate::{AttrVec, Attribute};
 
 /// Part of a `TokenStream`.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
@@ -767,8 +767,9 @@ impl DelimSpacing {
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(AttrTokenStream, 8);
     static_assert_size!(AttrTokenTree, 32);
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index cbc1afc6bf1..f39142f08ba 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -1,6 +1,7 @@
-use crate::token::CommentKind;
 use rustc_span::{BytePos, Symbol};
 
+use crate::token::CommentKind;
+
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs
index 11d50603a10..61bb2468e79 100644
--- a/compiler/rustc_ast/src/util/comments/tests.rs
+++ b/compiler/rustc_ast/src/util/comments/tests.rs
@@ -1,6 +1,7 @@
-use super::*;
 use rustc_span::create_default_session_globals_then;
 
+use super::*;
+
 #[test]
 fn test_block_doc_comment_1() {
     create_default_session_globals_then(|| {
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index cb73b7908c2..3bd2a80d361 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -1,15 +1,17 @@
 //! Code related to parsing literals.
 
-use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
-use crate::token::{self, Token};
+use std::{ascii, fmt, str};
+
 use rustc_lexer::unescape::{
     byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode,
 };
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-use std::{ascii, fmt, str};
 use tracing::debug;
 
+use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
+use crate::token::{self, Token};
+
 // Escapes a string, represented as a symbol. Reuses the original symbol,
 // avoiding interning, if no changes are required.
 pub fn escape_string_symbol(symbol: Symbol) -> Symbol {
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index ad92bf2cd40..8436c760d16 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -1,6 +1,7 @@
+use rustc_span::symbol::kw;
+
 use crate::ast::{self, BinOpKind};
 use crate::token::{self, BinOpToken, Token};
-use rustc_span::symbol::kw;
 
 /// Associative operator with precedence.
 ///
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index f6929057bed..fe07ec48f1f 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -13,14 +13,13 @@
 //! instance, a walker looking for item names in a module will miss all of
 //! those that are created by the expansion of a macro.
 
-use crate::ast::*;
-use crate::ptr::P;
-
+pub use rustc_ast_ir::visit::VisitorResult;
+pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-pub use rustc_ast_ir::visit::VisitorResult;
-pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list};
+use crate::ast::*;
+use crate::ptr::P;
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum AssocCtxt {
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 9ed93d481e7..0a7f75039f6 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -167,11 +167,23 @@ ast_lowering_template_modifier = template modifier
 
 ast_lowering_this_not_async = this is not `async`
 
+ast_lowering_underscore_array_length_unstable =
+    using `_` for array lengths is unstable
+
 ast_lowering_underscore_expr_lhs_assign =
     in expressions, `_` can only be used on the left-hand side of an assignment
     .label = `_` not allowed here
 
+ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
+ast_lowering_unstable_inline_assembly_const_operands =
+    const operands for inline assembly are unstable
+ast_lowering_unstable_inline_assembly_label_operands =
+    label operands for inline assembly are unstable
+ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
+
 ast_lowering_use_angle_brackets = use angle brackets instead
+
+ast_lowering_yield = yield syntax is experimental
 ast_lowering_yield_in_closure =
     `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
     .suggestion = use `#[coroutine]` to make this closure a coroutine
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index de0874af934..8acca78379b 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -1,13 +1,5 @@
-use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt};
-
-use super::errors::{
-    AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
-    InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
-    InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
-    InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
-    InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
-};
-use super::LoweringContext;
+use std::collections::hash_map::Entry;
+use std::fmt::Write;
 
 use rustc_ast::ptr::P;
 use rustc_ast::*;
@@ -18,11 +10,21 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Span};
 use rustc_target::asm;
-use std::collections::hash_map::Entry;
-use std::fmt::Write;
+
+use super::errors::{
+    AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
+    InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
+    InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
+    InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
+    InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
+};
+use super::LoweringContext;
+use crate::{
+    fluent_generated as fluent, ImplTraitContext, ImplTraitPosition, ParamMode,
+    ResolverAstLoweringExt,
+};
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     pub(crate) fn lower_inline_asm(
         &mut self,
         sp: Span,
@@ -52,7 +54,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     &self.tcx.sess,
                     sym::asm_experimental_arch,
                     sp,
-                    "inline assembly is not stable yet on this architecture",
+                    fluent::ast_lowering_unstable_inline_assembly,
                 )
                 .emit();
             }
@@ -64,8 +66,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
         }
         if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
-            feature_err(&self.tcx.sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable")
-                .emit();
+            feature_err(
+                &self.tcx.sess,
+                sym::asm_unwind,
+                sp,
+                fluent::ast_lowering_unstable_may_unwind,
+            )
+            .emit();
         }
 
         let mut clobber_abis = FxIndexMap::default();
@@ -182,7 +189,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 sess,
                                 sym::asm_const,
                                 *op_sp,
-                                "const operands for inline assembly are unstable",
+                                fluent::ast_lowering_unstable_inline_assembly_const_operands,
                             )
                             .emit();
                         }
@@ -246,7 +253,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 sess,
                                 sym::asm_goto,
                                 *op_sp,
-                                "label operands for inline assembly are unstable",
+                                fluent::ast_lowering_unstable_inline_assembly_label_operands,
                             )
                             .emit();
                         }
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index e821a08bf18..9d2b5690c23 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -1,9 +1,9 @@
-use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
 use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
 use rustc_hir as hir;
-
 use smallvec::SmallVec;
 
+use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
+
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     pub(super) fn lower_block(
         &mut self,
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 6df2c15ce60..300bfa101c6 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -33,26 +33,26 @@
 //! HIR ty lowering.
 //!
 //! Similarly generics, predicates and header are set to the "default" values.
-//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
+//! In case of discrepancy with callee function the `UnsupportedDelegation` error will
 //! also be emitted during HIR ty lowering.
 
-use crate::{ImplTraitPosition, ResolverAstLoweringExt};
-
-use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
+use std::iter;
 
 use ast::visit::Visitor;
 use hir::def::{DefKind, PartialRes, Res};
 use hir::{BodyId, HirId};
-use rustc_ast as ast;
 use rustc_ast::*;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{Asyncness, ResolverAstLowering};
-use rustc_span::{symbol::Ident, Span};
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
 use rustc_target::spec::abi;
-use std::iter;
+use {rustc_ast as ast, rustc_hir as hir};
+
+use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
+use crate::{ImplTraitPosition, ResolverAstLoweringExt};
 
 pub(crate) struct DelegationResults<'hir> {
     pub body_id: hir::BodyId,
@@ -275,8 +275,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
     // FIXME(fn_delegation): Alternatives for target expression lowering:
     // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
     fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
-        if block.stmts.len() == 1
-            && let StmtKind::Expr(expr) = &block.stmts[0].kind
+        if let [stmt] = block.stmts.as_slice()
+            && let StmtKind::Expr(expr) = &stmt.kind
         {
             return self.lower_expr_mut(expr);
         }
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 4c77892a6b7..7a6c9d8d0d3 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -1,8 +1,8 @@
-use rustc_errors::{
-    codes::*, Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic,
-};
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_span::{symbol::Ident, Span, Symbol};
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
 #[diag(ast_lowering_generic_type_with_parentheses, code = E0214)]
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index d870f9fe0ae..b5d8a547a8f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,15 +1,5 @@
 use std::assert_matches::assert_matches;
 
-use super::errors::{
-    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
-    ClosureCannotBeStatic, CoroutineTooManyParameters,
-    FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
-    NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign,
-};
-use super::ResolverAstLoweringExt;
-use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
-use crate::errors::YieldInClosure;
-use crate::{FnDeclKind, ImplTraitPosition};
 use rustc_ast::ptr::P as AstP;
 use rustc_ast::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -20,10 +10,21 @@ use rustc_middle::span_bug;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::DUMMY_SP;
-use rustc_span::{DesugaringKind, Span};
+use rustc_span::{DesugaringKind, Span, DUMMY_SP};
 use thin_vec::{thin_vec, ThinVec};
 
+use super::errors::{
+    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
+    ClosureCannotBeStatic, CoroutineTooManyParameters,
+    FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
+    NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign,
+};
+use super::{
+    ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs, ResolverAstLoweringExt,
+};
+use crate::errors::YieldInClosure;
+use crate::{fluent_generated, FnDeclKind, ImplTraitPosition};
+
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
         self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
@@ -1539,7 +1540,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
         let yielded =
             opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
@@ -1574,7 +1574,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         &self.tcx.sess,
                         sym::coroutines,
                         span,
-                        "yield syntax is experimental",
+                        fluent_generated::ast_lowering_yield,
                     )
                     .emit();
                 }
@@ -1586,7 +1586,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         &self.tcx.sess,
                         sym::coroutines,
                         span,
-                        "yield syntax is experimental",
+                        fluent_generated::ast_lowering_yield,
                     )
                     .emit();
                 }
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index ca4604c60c5..bf40c9b66c6 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -1,16 +1,14 @@
-use super::LoweringContext;
 use core::ops::ControlFlow;
-use rustc_ast as ast;
+use std::borrow::Cow;
+
 use rustc_ast::visit::Visitor;
 use rustc_ast::*;
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_hir as hir;
-use rustc_span::{
-    sym,
-    symbol::{kw, Ident},
-    Span, Symbol,
-};
-use std::borrow::Cow;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{sym, Span, Symbol};
+use {rustc_ast as ast, rustc_hir as hir};
+
+use super::LoweringContext;
 
 impl<'hir> LoweringContext<'_, 'hir> {
     pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 6e6aac1ddfc..7af3945d3f9 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,8 +1,3 @@
-use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
-use super::ResolverAstLoweringExt;
-use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
-use super::{FnDeclKind, LoweringContext, ParamMode};
-
 use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
@@ -22,6 +17,12 @@ use smallvec::{smallvec, SmallVec};
 use thin_vec::ThinVec;
 use tracing::instrument;
 
+use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
+use super::{
+    AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
+    ResolverAstLoweringExt,
+};
+
 pub(super) struct ItemLowerer<'a, 'hir> {
     pub(super) tcx: TyCtxt<'hir>,
     pub(super) resolver: &'a mut ResolverAstLowering,
@@ -1667,7 +1668,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             }),
                         )),
                     )),
-                    // FIXME(effects) we might not need a default.
                     default: Some(default_ct),
                     is_host_effect: true,
                     synthetic: true,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d44f953010a..81d17a9dec2 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -39,7 +39,8 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
-use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+use std::collections::hash_map::Entry;
+
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, *};
@@ -53,9 +54,9 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::{self as hir};
 use rustc_hir::{
-    ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
+    self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName,
+    TraitCandidate,
 };
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::extension;
@@ -65,10 +66,11 @@ use rustc_session::parse::{add_feature_diagnostics, feature_err};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{DesugaringKind, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
-use std::collections::hash_map::Entry;
 use thin_vec::ThinVec;
 use tracing::{debug, instrument, trace};
 
+use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+
 macro_rules! arena_vec {
     ($this:expr; $($x:expr),*) => (
         $this.arena.alloc_from_iter([$($x),*])
@@ -2324,7 +2326,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.expr_block(block)
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
         match c.value.kind {
             ExprKind::Underscore => {
@@ -2338,7 +2339,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         &self.tcx.sess,
                         sym::generic_arg_infer,
                         c.value.span,
-                        "using `_` for array lengths is unstable",
+                        fluent_generated::ast_lowering_underscore_array_length_unstable,
                     )
                     .stash(c.value.span, StashKey::UnderscoreForArrayLengths);
                     hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c))
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 5456abd489b..77cc2a36a53 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -1,4 +1,3 @@
-use super::ResolverAstLoweringExt;
 use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
 use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
 use rustc_data_structures::fx::FxIndexSet;
@@ -8,6 +7,8 @@ use rustc_middle::ty::ResolverAstLowering;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
+use super::ResolverAstLoweringExt;
+
 struct LifetimeCollectVisitor<'ast> {
     resolver: &'ast ResolverAstLowering,
     current_binders: Vec<NodeId>,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 32de07a0755..d82bdd526b7 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -1,17 +1,17 @@
-use super::errors::{
-    ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
-};
-use super::ResolverAstLoweringExt;
-use super::{ImplTraitContext, LoweringContext, ParamMode};
-use crate::ImplTraitPosition;
-
 use rustc_ast::ptr::P;
 use rustc_ast::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
-use rustc_span::{source_map::Spanned, Span};
+use rustc_span::Span;
+
+use super::errors::{
+    ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
+};
+use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
+use crate::ImplTraitPosition;
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index ac36b074609..077b06acd7c 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -1,13 +1,3 @@
-use crate::ImplTraitPosition;
-
-use super::errors::{
-    AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation,
-    GenericTypeWithParentheses, UseAngleBrackets,
-};
-use super::ResolverAstLoweringExt;
-use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
-use super::{ImplTraitContext, LoweringContext, ParamMode};
-
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
@@ -17,10 +7,19 @@ use rustc_hir::GenericArg;
 use rustc_middle::span_bug;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP};
-
 use smallvec::{smallvec, SmallVec};
 use tracing::{debug, instrument};
 
+use super::errors::{
+    AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation,
+    GenericTypeWithParentheses, UseAngleBrackets,
+};
+use super::{
+    GenericArgsCtor, ImplTraitContext, LifetimeRes, LoweringContext, ParamMode,
+    ParenthesizedGenericArgs, ResolverAstLoweringExt,
+};
+use crate::ImplTraitPosition;
+
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     #[instrument(level = "trace", skip(self))]
     pub(crate) fn lower_qpath(
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 9b063a330b7..a353c79f12d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -16,6 +16,9 @@
 //! constructions produced by proc macros. This pass is only intended for simple checks that do not
 //! require name resolution or type checking, or other kinds of complex analysis.
 
+use std::mem;
+use std::ops::{Deref, DerefMut};
+
 use itertools::{Either, Itertools};
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
@@ -34,8 +37,6 @@ use rustc_session::Session;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
-use std::mem;
-use std::ops::{Deref, DerefMut};
 use thin_vec::thin_vec;
 
 use crate::errors::{self, TildeConstReason};
@@ -452,11 +453,6 @@ impl<'a> AstValidator<'a> {
                             item_span: span,
                             block: Some(self.current_extern_span().shrink_to_lo()),
                         });
-                    } else if !self.features.unsafe_extern_blocks {
-                        self.dcx().emit_err(errors::InvalidSafetyOnExtern {
-                            item_span: span,
-                            block: None,
-                        });
                     }
                 }
             }
@@ -1053,32 +1049,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         errors::VisibilityNotPermittedNote::IndividualForeignItems,
                     );
 
-                    if this.features.unsafe_extern_blocks {
-                        if &Safety::Default == safety {
-                            if item.span.at_least_rust_2024() {
-                                this.dcx()
-                                    .emit_err(errors::MissingUnsafeOnExtern { span: item.span });
-                            } else {
-                                this.lint_buffer.buffer_lint(
-                                    MISSING_UNSAFE_ON_EXTERN,
-                                    item.id,
-                                    item.span,
-                                    BuiltinLintDiag::MissingUnsafeOnExtern {
-                                        suggestion: item.span.shrink_to_lo(),
-                                    },
-                                );
-                            }
+                    if &Safety::Default == safety {
+                        if item.span.at_least_rust_2024() {
+                            this.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
+                        } else {
+                            this.lint_buffer.buffer_lint(
+                                MISSING_UNSAFE_ON_EXTERN,
+                                item.id,
+                                item.span,
+                                BuiltinLintDiag::MissingUnsafeOnExtern {
+                                    suggestion: item.span.shrink_to_lo(),
+                                },
+                            );
                         }
-                    } else if let &Safety::Unsafe(span) = safety {
-                        let mut diag = this
-                            .dcx()
-                            .create_err(errors::UnsafeItem { span, kind: "extern block" });
-                        rustc_session::parse::add_feature_diagnostics(
-                            &mut diag,
-                            self.session,
-                            sym::unsafe_extern_blocks,
-                        );
-                        diag.emit();
                     }
 
                     if abi.is_none() {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 9151c4a7c7c..9e403680837 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -1,11 +1,11 @@
 //! Errors emitted by ast_passes.
 
 use rustc_ast::ParamKindOrd;
-use rustc_errors::{
-    codes::*, Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic,
-};
+use rustc_errors::codes::*;
+use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_span::{symbol::Ident, Span, Symbol};
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
 
 use crate::fluent_generated as fluent;
 
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index e91dfb27766..3ceb8e0711a 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,7 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{attr, NodeId};
-use rustc_ast::{token, PatKind};
+use rustc_ast::{attr, token, NodeId, PatKind};
 use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
 use rustc_session::Session;
@@ -561,10 +560,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
     gate_all!(global_registration, "global registration is experimental");
     gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
-    gate_all!(
-        unsafe_extern_blocks,
-        "`unsafe extern {}` blocks and `safe` keyword are experimental"
-    );
     gate_all!(return_type_notation, "return type notation is experimental");
 
     if !visitor.features.never_patterns {
diff --git a/compiler/rustc_ast_pretty/src/helpers.rs b/compiler/rustc_ast_pretty/src/helpers.rs
index c3e0eccd3d4..34641ea2f5a 100644
--- a/compiler/rustc_ast_pretty/src/helpers.rs
+++ b/compiler/rustc_ast_pretty/src/helpers.rs
@@ -1,6 +1,7 @@
-use crate::pp::Printer;
 use std::borrow::Cow;
 
+use crate::pp::Printer;
+
 impl Printer {
     pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
         self.word(w);
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 96f5eff6890..e4fd7e94fde 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -135,11 +135,11 @@
 mod convenience;
 mod ring;
 
-use ring::RingBuffer;
 use std::borrow::Cow;
-use std::cmp;
 use std::collections::VecDeque;
-use std::iter;
+use std::{cmp, iter};
+
+use ring::RingBuffer;
 
 /// How to break. Described in more detail in the module docs.
 #[derive(Clone, Copy, PartialEq)]
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
index c4c4fdce7fe..6d46c26311b 100644
--- a/compiler/rustc_ast_pretty/src/pp/convenience.rs
+++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs
@@ -1,6 +1,7 @@
-use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY};
 use std::borrow::Cow;
 
+use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY};
+
 impl Printer {
     /// "raw box"
     pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index 83b7e13905a..cfcc28ba76f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -2,13 +2,12 @@
 mod tests;
 
 pub mod state;
-pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State};
+use std::borrow::Cow;
 
 use rustc_ast as ast;
 use rustc_ast::token::{Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-
-use std::borrow::Cow;
+pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State};
 
 pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
     State::new().nonterminal_to_string(nt)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index b463d1f36ce..c7ff39d23ed 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -6,9 +6,8 @@ mod expr;
 mod fixup;
 mod item;
 
-use crate::pp::Breaks::{Consistent, Inconsistent};
-use crate::pp::{self, Breaks};
-use crate::pprust::state::fixup::FixupContext;
+use std::borrow::Cow;
+
 use ast::TraitBoundModifiers;
 use rustc_ast::attr::AttrIdGenerator;
 use rustc_ast::ptr::P;
@@ -16,18 +15,21 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To
 use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{Comment, CommentStyle};
-use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety};
-use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
-use rustc_ast::{GenericArg, GenericBound, SelfKind};
-use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::{
+    self as ast, attr, AttrArgs, AttrArgsEq, BindingMode, BlockCheckMode, ByRef, DelimArgs,
+    GenericArg, GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass,
+    InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term,
+};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
 use rustc_span::{BytePos, CharPos, FileName, Pos, Span, DUMMY_SP};
-use std::borrow::Cow;
 use thin_vec::ThinVec;
 
+use crate::pp::Breaks::{Consistent, Inconsistent};
+use crate::pp::{self, Breaks};
+use crate::pprust::state::fixup::FixupContext;
+
 pub enum MacHeader<'a> {
     Path(&'a ast::Path),
     Keyword(&'static str),
@@ -290,8 +292,7 @@ pub fn print_crate<'a>(
 fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
     use token::*;
     use Delimiter::*;
-    use TokenTree::Delimited as Del;
-    use TokenTree::Token as Tok;
+    use TokenTree::{Delimited as Del, Token as Tok};
 
     fn is_punct(tt: &TokenTree) -> bool {
         matches!(tt, TokenTree::Token(tok, _) if tok.is_punct())
@@ -501,8 +502,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                 if !self.is_beginning_of_line() {
                     self.word(" ");
                 }
-                if cmnt.lines.len() == 1 {
-                    self.word(cmnt.lines[0].clone());
+                if let [line] = cmnt.lines.as_slice() {
+                    self.word(line.clone());
                     self.hardbreak()
                 } else {
                     self.visual_align();
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 5b13858f839..b13c89c435d 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -1,19 +1,19 @@
-use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::fixup::FixupContext;
-use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+use std::fmt::Write;
+
 use ast::{ForLoopKind, MatchKind};
 use itertools::{Itertools, Position};
 use rustc_ast::ptr::P;
-use rustc_ast::token;
 use rustc_ast::util::classify;
 use rustc_ast::util::literal::escape_byte_str_symbol;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
-use rustc_ast::{self as ast, BlockCheckMode};
 use rustc_ast::{
-    FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign,
-    FormatTrait,
+    self as ast, token, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece,
+    FormatCount, FormatDebugHex, FormatSign, FormatTrait,
 };
-use std::fmt::Write;
+
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::fixup::FixupContext;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 
 impl<'a> State<'a> {
     fn print_else(&mut self, els: Option<&ast::Expr>) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index d8382057d3f..85a0b3b2022 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -1,7 +1,3 @@
-use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::fixup::FixupContext;
-use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
-
 use ast::StaticItem;
 use itertools::{Itertools, Position};
 use rustc_ast as ast;
@@ -9,6 +5,10 @@ use rustc_ast::ptr::P;
 use rustc_ast::ModKind;
 use rustc_span::symbol::Ident;
 
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::fixup::FixupContext;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+
 enum DelegationKind<'a> {
     Single,
     List(&'a [(Ident, Option<Ident>)]),
@@ -783,8 +783,8 @@ impl<'a> State<'a> {
                 }
                 if items.is_empty() {
                     self.word("{}");
-                } else if items.len() == 1 {
-                    self.print_use_tree(&items[0].0);
+                } else if let [(item, _)] = items.as_slice() {
+                    self.print_use_tree(item);
                 } else {
                     self.cbox(INDENT_UNIT);
                     self.word("{");
diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs
index 5b5ffbc6f88..3fefc523f88 100644
--- a/compiler/rustc_ast_pretty/src/pprust/tests.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs
@@ -1,11 +1,10 @@
-use super::*;
-
 use rustc_ast as ast;
-use rustc_span::create_default_session_globals_then;
 use rustc_span::symbol::Ident;
-use rustc_span::DUMMY_SP;
+use rustc_span::{create_default_session_globals_then, DUMMY_SP};
 use thin_vec::ThinVec;
 
+use super::*;
+
 fn fun_to_string(
     decl: &ast::FnDecl,
     header: ast::FnHeader,
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index eb51e568f81..5d9ac23ec49 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -104,6 +104,9 @@ attr_unknown_meta_item =
 attr_unknown_version_literal =
     unknown version literal format, assuming it refers to a future version
 
+attr_unstable_cfg_target_compact =
+    compact `cfg(target(..))` is experimental and subject to change
+
 attr_unsupported_literal_cfg_string =
     literal in `cfg` predicate value must be a string
 attr_unsupported_literal_deprecated_kv_pair =
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 34c24a26f7b..d057dcfdf9d 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -1,8 +1,12 @@
 //! Parsing and validation of builtin attributes
 
+use std::num::NonZero;
+
 use rustc_abi::Align;
-use rustc_ast::{self as ast, attr};
-use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
+use rustc_ast::{
+    self as ast, attr, Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem,
+    NodeId,
+};
 use rustc_ast_pretty::pprust;
 use rustc_errors::ErrorGuaranteed;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
@@ -13,9 +17,10 @@ use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::feature_err;
 use rustc_session::{RustcVersion, Session};
 use rustc_span::hygiene::Transparency;
-use rustc_span::{symbol::sym, symbol::Symbol, Span};
-use std::num::NonZero;
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
 
+use crate::fluent_generated;
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
 
 /// The version placeholder that recently stabilized features contain inside the
@@ -517,7 +522,6 @@ pub struct Condition {
 }
 
 /// Tests if a cfg-pattern matches the cfg set
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub fn cfg_matches(
     cfg: &ast::MetaItem,
     sess: &Session,
@@ -574,7 +578,7 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Fea
 /// Parse a rustc version number written inside string literal in an attribute,
 /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
 /// not accepted in this position, unlike when parsing CFG_RELEASE.
-fn parse_version(s: Symbol) -> Option<RustcVersion> {
+pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
     let mut components = s.as_str().split('-');
     let d = components.next()?;
     if components.next().is_some() {
@@ -589,7 +593,6 @@ fn parse_version(s: Symbol) -> Option<RustcVersion> {
 
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub fn eval_condition(
     cfg: &ast::MetaItem,
     sess: &Session,
@@ -661,12 +664,12 @@ pub fn eval_condition(
                         res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
                     }),
                 sym::not => {
-                    if mis.len() != 1 {
+                    let [mi] = mis.as_slice() else {
                         dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
                         return false;
-                    }
+                    };
 
-                    !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
+                    !eval_condition(mi.meta_item().unwrap(), sess, features, eval)
                 }
                 sym::target => {
                     if let Some(features) = features
@@ -676,7 +679,7 @@ pub fn eval_condition(
                             sess,
                             sym::cfg_target_compact,
                             cfg.span,
-                            "compact `cfg(target(..))` is experimental and subject to change",
+                            fluent_generated::attr_unstable_cfg_target_compact,
                         )
                         .emit();
                     }
@@ -1047,10 +1050,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     MetaItemKind::List(nested_items) => {
                         if meta_item.has_name(sym::align) {
                             recognised = true;
-                            if nested_items.len() == 1 {
+                            if let [nested_item] = nested_items.as_slice() {
                                 sess.dcx().emit_err(
                                     session_diagnostics::IncorrectReprFormatExpectInteger {
-                                        span: nested_items[0].span(),
+                                        span: nested_item.span(),
                                     },
                                 );
                             } else {
@@ -1062,10 +1065,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                             }
                         } else if meta_item.has_name(sym::packed) {
                             recognised = true;
-                            if nested_items.len() == 1 {
+                            if let [nested_item] = nested_items.as_slice() {
                                 sess.dcx().emit_err(
                                     session_diagnostics::IncorrectReprFormatPackedExpectInteger {
-                                        span: nested_items[0].span(),
+                                        span: nested_item.span(),
                                     },
                                 );
                             } else {
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index 9cc53ad7ad8..1ecfc42ec1d 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -15,12 +15,10 @@ mod builtin;
 mod session_diagnostics;
 
 pub use builtin::*;
+pub use rustc_ast::attr::*;
+pub(crate) use rustc_session::HashStableContext;
 pub use IntType::*;
 pub use ReprAttr::*;
 pub use StabilityLevel::*;
 
-pub use rustc_ast::attr::*;
-
-pub(crate) use rustc_session::HashStableContext;
-
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 0cffeed0a75..92a3a385a74 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -1,13 +1,12 @@
 use std::num::IntErrorKind;
 
 use rustc_ast as ast;
-use rustc_errors::DiagCtxtHandle;
-use rustc_errors::{codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level};
+use rustc_errors::codes::*;
+use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
-use crate::fluent_generated as fluent;
-use crate::UnsupportedLiteralReason;
+use crate::{fluent_generated as fluent, UnsupportedLiteralReason};
 
 #[derive(Diagnostic)]
 #[diag(attr_expected_one_cfg_pattern, code = E0536)]
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index c14a617eb91..edb25e12864 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -62,6 +62,9 @@ borrowck_could_not_normalize =
 borrowck_could_not_prove =
     could not prove `{$predicate}`
 
+borrowck_dereference_suggestion =
+    dereference the return value
+
 borrowck_func_take_self_moved_place =
     `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
 
@@ -74,9 +77,24 @@ borrowck_higher_ranked_lifetime_error =
 borrowck_higher_ranked_subtype_error =
     higher-ranked subtype error
 
+borrowck_implicit_static =
+    this has an implicit `'static` lifetime requirement
+
+borrowck_implicit_static_introduced =
+    calling this method introduces the `impl`'s `'static` requirement
+
+borrowck_implicit_static_relax =
+    consider relaxing the implicit `'static` requirement
+
 borrowck_lifetime_constraints_error =
     lifetime may not live long enough
 
+borrowck_limitations_implies_static =
+    due to current limitations in the borrow checker, this implies a `'static` lifetime
+
+borrowck_move_closure_suggestion =
+    consider adding 'move' keyword before the nested closure
+
 borrowck_move_out_place_here =
     {$place} is moved here
 
@@ -163,6 +181,9 @@ borrowck_partial_var_move_by_use_in_coroutine =
         *[false] moved
     } due to use in coroutine
 
+borrowck_restrict_to_static =
+    consider restricting the type parameter to the `'static` lifetime
+
 borrowck_returned_async_block_escaped =
     returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
 
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 0bae1bd07a2..51b420c441a 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -1,16 +1,17 @@
-use crate::path_utils::allow_two_phase_borrow;
-use crate::place_ext::PlaceExt;
-use crate::BorrowIndex;
+use std::fmt;
+use std::ops::Index;
+
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{self, Body, Local, Location};
+use rustc_middle::mir::{self, traversal, Body, Local, Location};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::move_paths::MoveData;
-use std::fmt;
-use std::ops::Index;
+
+use crate::path_utils::allow_two_phase_borrow;
+use crate::place_ext::PlaceExt;
+use crate::BorrowIndex;
 
 pub struct BorrowSet<'tcx> {
     /// The fundamental map relating bitvector indexes to the borrows
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 80deea14685..76e39fe94af 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -1,8 +1,8 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
-use rustc_errors::Applicability;
-use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, Diag, DiagCtxtHandle};
 use rustc_hir as hir;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty, TyCtxt};
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 540b466560c..0ae837898b9 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -4,11 +4,8 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
 use rustc_span::DUMMY_SP;
 
-use crate::{
-    constraints::OutlivesConstraintIndex,
-    constraints::{OutlivesConstraint, OutlivesConstraintSet},
-    type_check::Locations,
-};
+use crate::constraints::{OutlivesConstraint, OutlivesConstraintIndex, OutlivesConstraintSet};
+use crate::type_check::Locations;
 
 /// The construct graph organizes the constraints by their end-points.
 /// It can be used to view a `R1: R2` constraint as either an edge `R1
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index bb2fc3b67e9..7062632de66 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -1,12 +1,14 @@
-use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
-use crate::type_check::Locations;
-use crate::universal_regions::UniversalRegions;
+use std::fmt;
+use std::ops::Index;
+
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
 use rustc_span::Span;
-use std::fmt;
-use std::ops::Index;
+
+use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
+use crate::type_check::Locations;
+use crate::universal_regions::UniversalRegions;
 
 pub(crate) mod graph;
 
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index b9fa46ea883..8f560635cb3 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -1,24 +1,22 @@
 //! This file provides API for compiler consumers.
 
+use std::rc::Rc;
+
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::{Body, Promoted};
 use rustc_middle::ty::TyCtxt;
-use std::rc::Rc;
 
+pub use super::constraints::OutlivesConstraint;
+pub use super::dataflow::{calculate_borrows_out_of_scope_at_location, BorrowIndex, Borrows};
+pub use super::facts::{AllFacts as PoloniusInput, RustcFacts};
+pub use super::location::{LocationTable, RichLocation};
+pub use super::nll::PoloniusOutput;
+pub use super::place_ext::PlaceExt;
+pub use super::places_conflict::{places_conflict, PlaceConflictBias};
+pub use super::region_infer::RegionInferenceContext;
 use crate::borrow_set::BorrowSet;
 
-pub use super::{
-    constraints::OutlivesConstraint,
-    dataflow::{calculate_borrows_out_of_scope_at_location, BorrowIndex, Borrows},
-    facts::{AllFacts as PoloniusInput, RustcFacts},
-    location::{LocationTable, RichLocation},
-    nll::PoloniusOutput,
-    place_ext::PlaceExt,
-    places_conflict::{places_conflict, PlaceConflictBias},
-    region_infer::RegionInferenceContext,
-};
-
 /// Options determining the output behavior of [`get_body_with_borrowck_facts`].
 ///
 /// If executing under `-Z polonius` the choice here has no effect, and everything as if
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 59b3c6916cb..77794a8525f 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,16 +1,15 @@
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{
     self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
 };
-use rustc_middle::ty::RegionVid;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
-use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{fmt::DebugWithContext, GenKill};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, Results};
-use std::fmt;
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, Results, ResultsVisitable};
 
 use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index cbee01f2e2d..52eda721773 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -1,17 +1,18 @@
+use std::fmt;
+use std::rc::Rc;
+
 use rustc_errors::Diag;
 use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::infer::region_constraints::Constraint;
-use rustc_infer::infer::region_constraints::RegionConstraintData;
-use rustc_infer::infer::RegionVariableOrigin;
-use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
+use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
+use rustc_infer::infer::{
+    InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
+};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::RePlaceholder;
-use rustc_middle::ty::Region;
-use rustc_middle::ty::RegionVid;
-use rustc_middle::ty::UniverseIndex;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
+};
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -19,13 +20,10 @@ use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
 
-use std::fmt;
-use std::rc::Rc;
-
 use crate::region_infer::values::RegionElement;
-use crate::session_diagnostics::HigherRankedErrorCause;
-use crate::session_diagnostics::HigherRankedLifetimeError;
-use crate::session_diagnostics::HigherRankedSubtypeError;
+use crate::session_diagnostics::{
+    HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
+};
 use crate::MirBorrowckCtxt;
 
 #[derive(Clone)]
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 6fe50ad0d96..a58c7c43246 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3,25 +3,27 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use std::iter;
+use std::ops::ControlFlow;
+
 use either::Either;
 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};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, Diag, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_block, walk_expr, Map, Visitor};
-use rustc_hir::{CoroutineDesugaring, PatField};
-use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
+use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField};
 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,
     Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind, VarBindingForm,
+    TerminatorKind, VarBindingForm, VarDebugInfoContents,
 };
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
@@ -30,8 +32,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::util::CallKind;
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
-use rustc_span::def_id::DefId;
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, Symbol};
@@ -39,22 +40,14 @@ use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
-use std::iter;
-use std::ops::ControlFlow;
 
-use crate::borrow_set::TwoPhaseActivation;
-use crate::borrowck_errors;
+use super::explain_borrow::{BorrowExplanation, LaterUseKind};
+use super::{DescribePlaceOpt, RegionName, RegionNameSource, UseSpans};
+use crate::borrow_set::{BorrowData, TwoPhaseActivation};
 use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
-use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
-use crate::{
-    borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
-    InitializationRequiringAction, MirBorrowckCtxt, WriteKind,
-};
-
-use super::{
-    explain_borrow::{BorrowExplanation, LaterUseKind},
-    DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
-};
+use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt, Instance};
+use crate::prefixes::IsPrefixOf;
+use crate::{borrowck_errors, InitializationRequiringAction, MirBorrowckCtxt, WriteKind};
 
 #[derive(Debug)]
 struct MoveSite {
@@ -570,11 +563,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 } = move_spans
                     && can_suggest_clone
                 {
-                    self.suggest_cloning(err, ty, expr, None, Some(move_spans));
+                    self.suggest_cloning(err, ty, expr, Some(move_spans));
                 } 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));
+                    self.suggest_cloning(err, ty, expr, Some(move_spans));
                 }
             }
 
@@ -1131,8 +1124,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     err.multipart_suggestion(
                         "consider moving the expression out of the loop so it is only moved once",
                         vec![
-                            (parent.span, "value".to_string()),
                             (span.shrink_to_lo(), format!("let mut value = {value};{indent}")),
+                            (parent.span, "value".to_string()),
                         ],
                         Applicability::MaybeIncorrect,
                     );
@@ -1236,8 +1229,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         &self,
         err: &mut Diag<'_>,
         ty: Ty<'tcx>,
-        mut expr: &'tcx hir::Expr<'tcx>,
-        mut other_expr: Option<&'tcx hir::Expr<'tcx>>,
+        expr: &'tcx hir::Expr<'tcx>,
         use_spans: Option<UseSpans<'tcx>>,
     ) {
         if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
@@ -1249,66 +1241,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             return;
         }
 
-        if let Some(some_other_expr) = other_expr
-            && let Some(parent_binop) =
-                self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| {
-                    if let (hir_id, hir::Node::Expr(e)) = n
-                        && let hir::ExprKind::AssignOp(_binop, target, _arg) = e.kind
-                        && target.hir_id == expr.hir_id
-                    {
-                        Some(hir_id)
-                    } else {
-                        None
-                    }
-                })
-            && let Some(other_parent_binop) =
-                self.infcx.tcx.hir().parent_iter(some_other_expr.hir_id).find_map(|n| {
-                    if let (hir_id, hir::Node::Expr(expr)) = n
-                        && let hir::ExprKind::AssignOp(..) = expr.kind
-                    {
-                        Some(hir_id)
-                    } else {
-                        None
-                    }
-                })
-            && parent_binop == other_parent_binop
-        {
-            // Explicitly look for `expr += other_expr;` and avoid suggesting
-            // `expr.clone() += other_expr;`, instead suggesting `expr += other_expr.clone();`.
-            other_expr = Some(expr);
-            expr = some_other_expr;
-        }
-        'outer: {
-            if let ty::Ref(..) = ty.kind() {
-                // We check for either `let binding = foo(expr, other_expr);` or
-                // `foo(expr, other_expr);` and if so we don't suggest an incorrect
-                // `foo(expr, other_expr).clone()`
-                if let Some(other_expr) = other_expr
-                    && let Some(parent_let) =
-                        self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| {
-                            if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n {
-                                Some(hir_id)
-                            } else {
-                                None
-                            }
-                        })
-                    && let Some(other_parent_let) =
-                        self.infcx.tcx.hir().parent_iter(other_expr.hir_id).find_map(|n| {
-                            if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n {
-                                Some(hir_id)
-                            } else {
-                                None
-                            }
-                        })
-                    && parent_let == other_parent_let
-                {
-                    // Explicitly check that we don't have `foo(&*expr, other_expr)`, as cloning the
-                    // result of `foo(...)` won't help.
-                    break 'outer;
-                }
-            }
-        }
-        let ty = ty.peel_refs();
         if self.implements_clone(ty) {
             self.suggest_cloning_inner(err, ty, expr);
         } else if let ty::Adt(def, args) = ty.kind()
@@ -1580,10 +1512,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             );
         self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
         let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
-        if let Some(expr) = self.find_expr(borrow_span)
-            && let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
-        {
-            self.suggest_cloning(&mut err, ty, expr, self.find_expr(span), Some(move_spans));
+        if let Some(expr) = self.find_expr(borrow_span) {
+            // This is a borrow span, so we want to suggest cloning the referent.
+            if let hir::ExprKind::AddrOf(_, _, borrowed_expr) = expr.kind
+                && let Some(ty) = typeck_results.expr_ty_opt(borrowed_expr)
+            {
+                self.suggest_cloning(&mut err, ty, borrowed_expr, Some(move_spans));
+            } else if typeck_results.expr_adjustments(expr).first().is_some_and(|adj| {
+                matches!(
+                    adj.kind,
+                    ty::adjustment::Adjust::Borrow(ty::adjustment::AutoBorrow::Ref(
+                        _,
+                        ty::adjustment::AutoBorrowMutability::Not
+                            | ty::adjustment::AutoBorrowMutability::Mut {
+                                allow_two_phase_borrow: ty::adjustment::AllowTwoPhase::No
+                            }
+                    ))
+                )
+            }) && let Some(ty) = typeck_results.expr_ty_opt(expr)
+            {
+                self.suggest_cloning(&mut err, ty, expr, Some(move_spans));
+            }
         }
         self.buffer_error(err);
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index ffe52f939dd..d85959c9a29 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -3,6 +3,8 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use std::assert_matches::assert_matches;
+
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
@@ -19,13 +21,11 @@ use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{sym, DesugaringKind, Span};
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 
-use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
-use crate::{
-    borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
-    WriteKind,
-};
-
 use super::{find_use, RegionName, UseSpans};
+use crate::borrow_set::BorrowData;
+use crate::nll::ConstraintDescription;
+use crate::region_infer::{BlameConstraint, Cause, ExtraConstraintInfo};
+use crate::{MirBorrowckCtxt, WriteKind};
 
 #[derive(Debug)]
 pub(crate) enum BorrowExplanation<'tcx> {
@@ -118,7 +118,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                     // path_span must be `Some` as otherwise the if condition is true
                     let path_span = path_span.unwrap();
                     // path_span is only present in the case of closure capture
-                    assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+                    assert_matches!(later_use_kind, LaterUseKind::ClosureCapture);
                     if !borrow_span.is_some_and(|sp| sp.overlaps(var_or_use_span)) {
                         let path_label = "used here by closure";
                         let capture_kind_label = message;
@@ -149,7 +149,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                     // path_span must be `Some` as otherwise the if condition is true
                     let path_span = path_span.unwrap();
                     // path_span is only present in the case of closure capture
-                    assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+                    assert_matches!(later_use_kind, LaterUseKind::ClosureCapture);
                     if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
                         let path_label = "used here by closure";
                         let capture_kind_label = message;
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
index 94b17e0a2f9..bea8d3bfdfb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
@@ -1,15 +1,14 @@
 use std::collections::VecDeque;
 use std::rc::Rc;
 
-use crate::{
-    def_use::{self, DefUse},
-    region_infer::{Cause, RegionInferenceContext},
-};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{RegionVid, TyCtxt};
 
+use crate::def_use::{self, DefUse};
+use crate::region_infer::{Cause, RegionInferenceContext};
+
 pub(crate) fn find<'tcx>(
     body: &Body<'tcx>,
     regioncx: &Rc<RegionInferenceContext<'tcx>>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index d505d9c004e..a2e5c7b8514 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1,14 +1,8 @@
 //! Borrow checker diagnostics.
 
-use crate::session_diagnostics::{
-    CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
-    CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
-};
-use rustc_errors::MultiSpan;
-use rustc_errors::{Applicability, Diag};
+use rustc_errors::{Applicability, Diag, MultiSpan};
 use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::CoroutineKind;
-use rustc_hir::{self as hir, LangItem};
+use rustc_hir::{self as hir, CoroutineKind, LangItem};
 use rustc_index::IndexSlice;
 use rustc_infer::infer::BoundRegionConversionTime;
 use rustc_infer::traits::SelectionError;
@@ -25,7 +19,8 @@ use rustc_middle::util::{call_kind, CallDesugaringKind};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Spanned;
-use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
+use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -33,10 +28,13 @@ use rustc_trait_selection::traits::{
     type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode,
 };
 
-use crate::fluent_generated as fluent;
-
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
+use crate::fluent_generated as fluent;
+use crate::session_diagnostics::{
+    CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
+    CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
+};
 
 mod find_all_local_uses;
 mod find_use;
@@ -599,8 +597,9 @@ impl UseSpans<'_> {
         err: &mut Diag<'_>,
         action: crate::InitializationRequiringAction,
     ) {
-        use crate::InitializationRequiringAction::*;
         use CaptureVarPathUseCause::*;
+
+        use crate::InitializationRequiringAction::*;
         if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
             match closure_kind {
                 hir::ClosureKind::Coroutine(_) => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index fcf23aa4785..792f1548e08 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -11,8 +11,7 @@ use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 
-use crate::diagnostics::CapturedMessageOpt;
-use crate::diagnostics::{DescribePlaceOpt, UseSpans};
+use crate::diagnostics::{CapturedMessageOpt, DescribePlaceOpt, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -565,9 +564,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
 
     fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
         match error {
-            GroupedMoveError::MovesFromPlace {
-                mut binds_to, move_from, span: other_span, ..
-            } => {
+            GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
                 self.add_borrow_suggestions(err, span);
                 if binds_to.is_empty() {
                     let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
@@ -577,7 +574,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     };
 
                     if let Some(expr) = self.find_expr(span) {
-                        self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None);
+                        self.suggest_cloning(err, place_ty, expr, None);
                     }
 
                     err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
@@ -609,13 +606,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 };
 
                 if let Some(expr) = self.find_expr(use_span) {
-                    self.suggest_cloning(
-                        err,
-                        place_ty,
-                        expr,
-                        self.find_expr(span),
-                        Some(use_spans),
-                    );
+                    self.suggest_cloning(err, place_ty, expr, Some(use_spans));
                 }
 
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
@@ -740,7 +731,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
 
                 if let Some(expr) = self.find_expr(binding_span) {
-                    self.suggest_cloning(err, bind_to.ty, expr, None, None);
+                    self.suggest_cloning(err, bind_to.ty, expr, None);
                 }
 
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a7bf6d636c1..0303b80cace 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -2,17 +2,18 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use core::ops::ControlFlow;
+
 use hir::{ExprKind, Param};
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, BindingMode, ByRef, Node};
 use rustc_middle::bug;
-use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
-use rustc_middle::{
-    hir::place::PlaceBase,
-    mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
+use rustc_middle::hir::place::PlaceBase;
+use rustc_middle::mir::{
+    self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location, Mutability, Place,
+    PlaceRef, ProjectionElem,
 };
+use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{sym, BytePos, DesugaringKind, Span};
 use rustc_target::abi::FieldIdx;
@@ -847,10 +848,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     // Attempt to search similar mutable associated items for suggestion.
     // In the future, attempt in all path but initially for RHS of for_loop
     fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diag<'_>, span: Span) {
-        use hir::{
-            BorrowKind, Expr,
-            ExprKind::{AddrOf, Block, Call, MethodCall},
-        };
+        use hir::ExprKind::{AddrOf, Block, Call, MethodCall};
+        use hir::{BorrowKind, Expr};
 
         let hir_map = self.infcx.tcx.hir();
         struct Finder {
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 082111a642c..de0df347429 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -4,15 +4,15 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use std::collections::BTreeMap;
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diag;
 use rustc_middle::ty::RegionVid;
 use smallvec::SmallVec;
-use std::collections::BTreeMap;
-
-use crate::MirBorrowckCtxt;
 
 use super::{ErrorConstraintInfo, RegionName, RegionNameSource};
+use crate::MirBorrowckCtxt;
 
 /// The different things we could suggest.
 enum SuggestedConstraint {
@@ -206,8 +206,8 @@ impl OutlivesSuggestionBuilder {
 
         // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
         // list of diagnostics.
-        let mut diag = if suggested.len() == 1 {
-            mbcx.dcx().struct_help(match suggested.last().unwrap() {
+        let mut diag = if let [constraint] = suggested.as_slice() {
+            mbcx.dcx().struct_help(match constraint {
                 SuggestedConstraint::Outlives(a, bs) => {
                     let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
                     format!("add bound `{a}: {}`", bs.join(" + "))
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 6b7bd7dc0d8..451e8bcb16d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -14,10 +14,7 @@ use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
 use rustc_middle::bug;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::TypeVisitor;
-use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_middle::ty::{Region, TyCtxt};
+use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::infer::nice_region_error::{
@@ -29,20 +26,16 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
 
-use crate::borrowck_errors;
+use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
+use crate::nll::ConstraintDescription;
+use crate::region_infer::values::RegionElement;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo, TypeTest};
 use crate::session_diagnostics::{
     FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
     LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
 };
-
-use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
-use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
-use crate::{
-    nll::ConstraintDescription,
-    region_infer::{values::RegionElement, TypeTest},
-    universal_regions::DefiningTy,
-    MirBorrowckCtxt,
-};
+use crate::universal_regions::DefiningTy;
+use crate::{borrowck_errors, fluent_generated as fluent, MirBorrowckCtxt};
 
 impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
     fn description(&self) -> &'static str {
@@ -205,7 +198,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
     // and the span which bounded to the trait for adding 'static lifetime suggestion
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn suggest_static_lifetime_for_gat_from_hrtb(
         &self,
         diag: &mut Diag<'_>,
@@ -258,23 +250,28 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         debug!(?hrtb_bounds);
 
         hrtb_bounds.iter().for_each(|bound| {
-            let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
-            diag.span_note(
-                *trait_span,
-                "due to current limitations in the borrow checker, this implies a `'static` lifetime"
-            );
-            let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; };
-            let Def(_, trait_res_defid) = trait_ref.path.res else { return; };
+            let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else {
+                return;
+            };
+            diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
+            let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local())
+            else {
+                return;
+            };
+            let Def(_, trait_res_defid) = trait_ref.path.res else {
+                return;
+            };
             debug!(?generics_fn);
             generics_fn.predicates.iter().for_each(|predicate| {
-                let BoundPredicate(
-                    WhereBoundPredicate {
-                        span: bounded_span,
-                        bounded_ty,
-                        bounds,
-                        ..
-                    }
-                ) = predicate else { return; };
+                let BoundPredicate(WhereBoundPredicate {
+                    span: bounded_span,
+                    bounded_ty,
+                    bounds,
+                    ..
+                }) = predicate
+                else {
+                    return;
+                };
                 bounds.iter().for_each(|bd| {
                     if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd
                         && let Def(_, res_defid) = tr_ref.path.res
@@ -284,16 +281,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                         && generics_fn.params
                             .iter()
                             .rfind(|param| param.def_id.to_def_id() == defid)
-                            .is_some() {
-                            suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
-                        }
+                            .is_some()
+                    {
+                        suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
+                    }
                 });
             });
         });
         if suggestions.len() > 0 {
             suggestions.dedup();
             diag.multipart_suggestion_verbose(
-                "consider restricting the type parameter to the `'static` lifetime",
+                fluent::borrowck_restrict_to_static,
                 suggestions,
                 Applicability::MaybeIncorrect,
             );
@@ -983,7 +981,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     #[instrument(skip(self, err), level = "debug")]
     fn suggest_constrain_dyn_trait_in_impl(
         &self,
@@ -1001,16 +998,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             debug!("trait spans found: {:?}", traits);
             for span in &traits {
                 let mut multi_span: MultiSpan = vec![*span].into();
-                multi_span
-                    .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
-                multi_span.push_span_label(
-                    ident.span,
-                    "calling this method introduces the `impl`'s `'static` requirement",
-                );
+                multi_span.push_span_label(*span, fluent::borrowck_implicit_static);
+                multi_span.push_span_label(ident.span, fluent::borrowck_implicit_static_introduced);
                 err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
-                    "consider relaxing the implicit `'static` requirement",
+                    fluent::borrowck_implicit_static_relax,
                     " + '_",
                     Applicability::MaybeIncorrect,
                 );
@@ -1052,7 +1045,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     /// When encountering a lifetime error caused by the return type of a closure, check the
     /// corresponding trait bound and see if dereferencing the closure return value would satisfy
     /// them. If so, we produce a structured suggestion.
@@ -1173,7 +1165,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         if ocx.select_all_or_error().is_empty() && count > 0 {
             diag.span_suggestion_verbose(
                 tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
-                "dereference the return value",
+                fluent::borrowck_dereference_suggestion,
                 "*".repeat(count),
                 Applicability::MachineApplicable,
             );
@@ -1181,7 +1173,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
         let map = self.infcx.tcx.hir();
         let body = map.body_owned_by(self.mir_def_id());
@@ -1220,7 +1211,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         if let Some(closure_span) = closure_span {
             diag.span_suggestion_verbose(
                 closure_span,
-                "consider adding 'move' keyword before the nested closure",
+                fluent::borrowck_move_closure_suggestion,
                 "move ",
                 Applicability::MaybeIncorrect,
             );
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 6443c5e92e8..12aedf6fe08 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -9,14 +9,14 @@ use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::print::RegionHighlightMode;
-use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, RegionVid, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 
-use crate::{universal_regions::DefiningTy, MirBorrowckCtxt};
+use crate::universal_regions::DefiningTy;
+use crate::MirBorrowckCtxt;
 
 /// A name for a particular region used in emitting diagnostics. This name could be a generated
 /// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 0479cd8af35..3e9f975b66b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -1,10 +1,11 @@
-use crate::region_infer::RegionInferenceContext;
 use rustc_index::IndexSlice;
 use rustc_middle::mir::{Body, Local};
 use rustc_middle::ty::{self, RegionVid, TyCtxt};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use crate::region_infer::RegionInferenceContext;
+
 impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn get_var_name_and_span_for_region(
         &self,
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index af96f115385..94b50448576 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -1,17 +1,18 @@
-use crate::location::{LocationIndex, LocationTable};
-use crate::BorrowIndex;
-use polonius_engine::AllFacts as PoloniusFacts;
-use polonius_engine::Atom;
-use rustc_macros::extension;
-use rustc_middle::mir::Local;
-use rustc_middle::ty::{RegionVid, TyCtxt};
-use rustc_mir_dataflow::move_paths::MovePathIndex;
 use std::error::Error;
 use std::fmt::Debug;
 use std::fs::{self, File};
 use std::io::{BufWriter, Write};
 use std::path::Path;
 
+use polonius_engine::{AllFacts as PoloniusFacts, Atom};
+use rustc_macros::extension;
+use rustc_middle::mir::Local;
+use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_mir_dataflow::move_paths::MovePathIndex;
+
+use crate::location::{LocationIndex, LocationTable};
+use crate::BorrowIndex;
+
 #[derive(Copy, Clone, Debug)]
 pub struct RustcFacts;
 
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 9ad941dabbe..9c2a0036bef 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -17,6 +17,13 @@
 #[macro_use]
 extern crate tracing;
 
+use std::cell::RefCell;
+use std::collections::BTreeMap;
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::rc::Rc;
+
+use consumers::{BodyWithBorrowckFacts, ConsumerOptions};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_errors::Diag;
@@ -24,40 +31,31 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::{BitSet, ChunkedBitSet};
 use rustc_index::{IndexSlice, IndexVec};
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
+use rustc_infer::infer::{
+    InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
+};
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_session::lint::builtin::UNUSED_MUT;
-use rustc_span::{Span, Symbol};
-use rustc_target::abi::FieldIdx;
-
-use smallvec::SmallVec;
-use std::cell::RefCell;
-use std::collections::BTreeMap;
-use std::marker::PhantomData;
-use std::ops::Deref;
-use std::rc::Rc;
-
 use rustc_mir_dataflow::impls::{
     EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
 };
-use rustc_mir_dataflow::move_paths::{InitIndex, MoveOutIndex, MovePathIndex};
-use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData};
+use rustc_mir_dataflow::move_paths::{
+    InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
+};
 use rustc_mir_dataflow::Analysis;
-use rustc_mir_dataflow::MoveDataParamEnv;
-
-use crate::session_diagnostics::VarNeedNotMut;
+use rustc_session::lint::builtin::UNUSED_MUT;
+use rustc_span::{Span, Symbol};
+use rustc_target::abi::FieldIdx;
+use smallvec::SmallVec;
 
 use self::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
 use self::location::LocationTable;
-use self::prefixes::PrefixSet;
-use consumers::{BodyWithBorrowckFacts, ConsumerOptions};
-
 use self::path_utils::*;
+use self::prefixes::PrefixSet;
+use crate::session_diagnostics::VarNeedNotMut;
 
 pub mod borrow_set;
 mod borrowck_errors;
@@ -196,9 +194,7 @@ fn do_mir_borrowck<'tcx>(
         .iter_enumerated()
         .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true)));
 
-    let mdpe = MoveDataParamEnv { move_data, param_env };
-
-    let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+    let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint()
@@ -206,7 +202,7 @@ fn do_mir_borrowck<'tcx>(
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
     let borrow_set =
-        Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
+        Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data));
 
     // Compute non-lexical lifetimes.
     let nll::NllOutput {
@@ -224,7 +220,7 @@ fn do_mir_borrowck<'tcx>(
         &location_table,
         param_env,
         &mut flow_inits,
-        &mdpe.move_data,
+        &move_data,
         &borrow_set,
         tcx.closure_captures(def),
         consumer_options,
@@ -256,11 +252,11 @@ fn do_mir_borrowck<'tcx>(
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
+    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_ever_inits = EverInitializedPlaces::new(body, &mdpe)
+    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
@@ -326,7 +322,7 @@ fn do_mir_borrowck<'tcx>(
         infcx: &infcx,
         param_env,
         body,
-        move_data: &mdpe.move_data,
+        move_data: &move_data,
         location_table: &location_table,
         movable_coroutine,
         locals_are_invalidated_at_exit,
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index 5129b32d492..499c32396d0 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -1,11 +1,12 @@
+use std::hash::Hash;
+use std::ops::Index;
+
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::infer::MemberConstraint;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
-use std::hash::Hash;
-use std::ops::Index;
 
 /// Compactly stores a set of `R0 member of [R1...Rn]` constraints,
 /// indexed by the region `R0`.
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 2ffa9ba5b4d..af37c028879 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -1,11 +1,18 @@
 //! The entry point of the NLL borrow checker.
 
+use std::path::PathBuf;
+use std::rc::Rc;
+use std::str::FromStr;
+use std::{env, io};
+
 use polonius_engine::{Algorithm, Output};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::IndexSlice;
-use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
-use rustc_middle::mir::{Body, ClosureOutlivesSubject, ClosureRegionRequirements, Promoted};
+use rustc_middle::mir::{
+    create_dump_file, dump_enabled, dump_mir, Body, ClosureOutlivesSubject,
+    ClosureRegionRequirements, PassWhere, Promoted,
+};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
@@ -13,25 +20,16 @@ use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_mir_dataflow::ResultsCursor;
 use rustc_span::symbol::sym;
-use std::env;
-use std::io;
-use std::path::PathBuf;
-use std::rc::Rc;
-use std::str::FromStr;
 
-use crate::{
-    borrow_set::BorrowSet,
-    consumers::ConsumerOptions,
-    diagnostics::RegionErrors,
-    facts::{AllFacts, AllFactsExt, RustcFacts},
-    location::LocationTable,
-    polonius,
-    region_infer::RegionInferenceContext,
-    renumber,
-    type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
-    universal_regions::UniversalRegions,
-    BorrowckInferCtxt,
-};
+use crate::borrow_set::BorrowSet;
+use crate::consumers::ConsumerOptions;
+use crate::diagnostics::RegionErrors;
+use crate::facts::{AllFacts, AllFactsExt, RustcFacts};
+use crate::location::LocationTable;
+use crate::region_infer::RegionInferenceContext;
+use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults};
+use crate::universal_regions::UniversalRegions;
+use crate::{polonius, renumber, BorrowckInferCtxt};
 
 pub type PoloniusOutput = Output<RustcFacts>;
 
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index 88b20bba9fb..4afb41be18f 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -1,13 +1,11 @@
-use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
-use crate::places_conflict;
-use crate::AccessDepth;
-use crate::BorrowIndex;
 use rustc_data_structures::graph::dominators::Dominators;
-use rustc_middle::mir::BorrowKind;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem};
+use rustc_middle::mir::{BasicBlock, Body, BorrowKind, Location, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::TyCtxt;
 use rustc_target::abi::FieldIdx;
 
+use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
+use crate::{places_conflict, AccessDepth, BorrowIndex};
+
 /// Returns `true` if the borrow represented by `kind` is
 /// allowed to be split into separate Reservation and
 /// Activation phases.
diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
index 0f806df9da1..ce63d51682e 100644
--- a/compiler/rustc_borrowck/src/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -1,10 +1,10 @@
-use crate::borrow_set::LocalsStateAtExit;
 use rustc_hir as hir;
 use rustc_macros::extension;
-use rustc_middle::mir::ProjectionElem;
-use rustc_middle::mir::{Body, Mutability, Place};
+use rustc_middle::mir::{Body, Mutability, Place, ProjectionElem};
 use rustc_middle::ty::{self, TyCtxt};
 
+use crate::borrow_set::LocalsStateAtExit;
+
 #[extension(pub trait PlaceExt<'tcx>)]
 impl<'tcx> Place<'tcx> {
     /// Returns `true` if we can safely ignore borrows of this place.
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index ad3c3e6d079..42d0c2038f8 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -50,17 +50,17 @@
 //!    and either equal or disjoint.
 //!  - If we did run out of access, the borrow can access a part of it.
 
-use crate::ArtificialField;
-use crate::Overlap;
-use crate::{AccessDepth, Deep, Shallow};
+use std::cmp::max;
+use std::iter;
+
 use rustc_hir as hir;
 use rustc_middle::bug;
 use rustc_middle::mir::{
     Body, BorrowKind, FakeBorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
 };
 use rustc_middle::ty::{self, TyCtxt};
-use std::cmp::max;
-use std::iter;
+
+use crate::{AccessDepth, ArtificialField, Deep, Overlap, Shallow};
 
 /// When checking if a place conflicts with another place, this enum is used to influence decisions
 /// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index 30dfc4c21b0..f090da031a0 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -2,17 +2,19 @@ use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::bug;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{
-    self, BasicBlock, Body, FakeBorrowKind, Location, NonDivergingIntrinsic, Place, Rvalue,
+    self, BasicBlock, Body, BorrowKind, FakeBorrowKind, InlineAsmOperand, Location, Mutability,
+    NonDivergingIntrinsic, Operand, Place, Rvalue, Statement, StatementKind, Terminator,
+    TerminatorKind,
 };
-use rustc_middle::mir::{BorrowKind, Mutability, Operand};
-use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
-use rustc_middle::mir::{Statement, StatementKind};
 use rustc_middle::ty::TyCtxt;
 
+use crate::borrow_set::BorrowSet;
+use crate::facts::AllFacts;
+use crate::location::LocationTable;
+use crate::path_utils::*;
 use crate::{
-    borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
-    Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind,
-    ReadOrWrite, Reservation, Shallow, Write, WriteKind,
+    AccessDepth, Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read,
+    ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteKind,
 };
 
 /// Emit `loan_invalidated_at` facts.
diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs
index 53adad5561e..d85c2175bed 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs
@@ -5,7 +5,10 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::TyCtxt;
 
-use crate::{borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict};
+use crate::borrow_set::BorrowSet;
+use crate::facts::AllFacts;
+use crate::location::LocationTable;
+use crate::places_conflict;
 
 /// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
 pub(super) fn emit_loan_kills<'tcx>(
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 5d3ac1c409a..d3bfd1c418f 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -4,10 +4,10 @@
 //! is borrowed. But: writing `a` is legal if `*a` is borrowed,
 //! whether or not `a` is a shared or mutable reference. [...] "
 
-use super::MirBorrowckCtxt;
-
 use rustc_middle::mir::{PlaceRef, ProjectionElem};
 
+use super::MirBorrowckCtxt;
+
 pub trait IsPrefixOf<'tcx> {
     fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool;
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index 53541b33c41..6b8dd1a49e7 100644
--- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -3,11 +3,13 @@
 //! state of region inference. This code handles emitting the region
 //! context internal state.
 
-use super::{OutlivesConstraint, RegionInferenceContext};
-use crate::type_check::Locations;
+use std::io::{self, Write};
+
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::TyCtxt;
-use std::io::{self, Write};
+
+use super::{OutlivesConstraint, RegionInferenceContext};
+use crate::type_check::Locations;
 
 // Room for "'_#NNNNr" before things get misaligned.
 // Easy enough to fix if this ever doesn't seem like
diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
index f145d30fe38..743864dd535 100644
--- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs
+++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
@@ -5,11 +5,12 @@
 use std::borrow::Cow;
 use std::io::{self, Write};
 
-use super::*;
 use itertools::Itertools;
 use rustc_graphviz as dot;
 use rustc_middle::ty::UniverseIndex;
 
+use super::*;
+
 fn render_outlives_constraint(constraint: &OutlivesConstraint<'_>) -> String {
     match constraint.locations {
         Locations::All(_) => "All(...)".to_string(),
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 44a84fb9d7f..c8dc012de4a 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -17,27 +17,25 @@ use rustc_middle::mir::{
     ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
     TerminatorKind,
 };
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
 use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::Span;
 
 use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
+use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet};
 use crate::dataflow::BorrowIndex;
-use crate::{
-    constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet},
-    diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
-    member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
-    nll::PoloniusOutput,
-    region_infer::reverse_sccs::ReverseSccGraph,
-    region_infer::values::{
-        LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
-    },
-    type_check::{free_region_relations::UniversalRegionRelations, Locations},
-    universal_regions::UniversalRegions,
-    BorrowckInferCtxt,
+use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
+use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
+use crate::nll::PoloniusOutput;
+use crate::region_infer::reverse_sccs::ReverseSccGraph;
+use crate::region_infer::values::{
+    LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
 };
+use crate::type_check::free_region_relations::UniversalRegionRelations;
+use crate::type_check::Locations;
+use crate::universal_regions::UniversalRegions;
+use crate::BorrowckInferCtxt;
 
 mod dump_mir;
 mod graphviz;
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index cf28ba224d6..1073ea40694 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -3,22 +3,20 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::TyCtxtInferExt as _;
-use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
 use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_macros::extension;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{GenericArgKind, GenericArgs};
+use rustc_middle::ty::{
+    self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
+};
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 
-use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
-use crate::session_diagnostics::NonGenericOpaqueTypeParam;
-use crate::universal_regions::RegionClassification;
-
 use super::RegionInferenceContext;
+use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTypeParam};
+use crate::universal_regions::RegionClassification;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
     /// Resolve any opaque types that were encountered while borrow checking
@@ -227,21 +225,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
                 // Find something that we can name
                 let upper_bound = self.approx_universal_upper_bound(vid);
-                let upper_bound = &self.definitions[upper_bound];
-                match upper_bound.external_name {
-                    Some(reg) => reg,
-                    None => {
-                        // Nothing exact found, so we pick the first one that we find.
-                        let scc = self.constraint_sccs.scc(vid);
-                        for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
-                            match self.definitions[vid].external_name {
-                                None => {}
-                                Some(region) if region.is_static() => {}
-                                Some(region) => return region,
-                            }
-                        }
-                        region
-                    }
+                if let Some(universal_region) = self.definitions[upper_bound].external_name {
+                    return universal_region;
+                }
+
+                // Nothing exact found, so we pick a named upper bound, if there's only one.
+                // If there's >1 universal region, then we probably are dealing w/ an intersection
+                // region which cannot be mapped back to a universal.
+                // FIXME: We could probably compute the LUB if there is one.
+                let scc = self.constraint_sccs.scc(vid);
+                let upper_bounds: Vec<_> = self
+                    .rev_scc_graph
+                    .as_ref()
+                    .unwrap()
+                    .upper_bounds(scc)
+                    .filter_map(|vid| self.definitions[vid].external_name)
+                    .filter(|r| !r.is_static())
+                    .collect();
+                match &upper_bounds[..] {
+                    [universal_region] => *universal_region,
+                    _ => region,
                 }
             }
             _ => region,
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index 97ddc45ee47..3cc5fa4404e 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -1,10 +1,12 @@
-use crate::constraints::ConstraintSccIndex;
-use crate::RegionInferenceContext;
+use std::ops::Range;
+
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph;
 use rustc_data_structures::graph::vec_graph::VecGraph;
 use rustc_middle::ty::RegionVid;
-use std::ops::Range;
+
+use crate::constraints::ConstraintSccIndex;
+use crate::RegionInferenceContext;
 
 pub(crate) struct ReverseSccGraph {
     graph: VecGraph<ConstraintSccIndex>,
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index b1caaa63881..1e91130bdc5 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -1,14 +1,13 @@
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::fx::FxIndexSet;
+use std::fmt::Debug;
+use std::rc::Rc;
+
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_index::bit_set::SparseBitMatrix;
-use rustc_index::interval::IntervalSet;
-use rustc_index::interval::SparseIntervalMatrix;
+use rustc_index::interval::{IntervalSet, SparseIntervalMatrix};
 use rustc_index::Idx;
 use rustc_middle::mir::{BasicBlock, Location};
 use rustc_middle::ty::{self, RegionVid};
 use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
-use std::fmt::Debug;
-use std::rc::Rc;
 
 use crate::BorrowIndex;
 
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 2858a407e09..2a3b51532e5 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,12 +1,12 @@
-use crate::BorrowckInferCtxt;
 use rustc_index::IndexSlice;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::mir::visit::{MutVisitor, TyContext};
 use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Symbol;
 
+use crate::BorrowckInferCtxt;
+
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
 #[instrument(skip(infcx, body, promoted), level = "debug")]
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 40c2ef1c91e..4a50b0f0704 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -1,4 +1,5 @@
-use rustc_errors::{codes::*, MultiSpan};
+use rustc_errors::codes::*;
+use rustc_errors::MultiSpan;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{GenericArg, Ty};
 use rustc_span::Span;
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 2dc2568cd47..b58691fbeae 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -7,12 +7,12 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
+use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
 use rustc_trait_selection::traits::ObligationCause;
 
-use crate::diagnostics::ToUniverseInfo;
-
 use super::{Locations, NormalizeLocation, TypeChecker};
+use crate::diagnostics::ToUniverseInfo;
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// Given some operation `op` that manipulates types, proves
@@ -167,6 +167,52 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
+    pub(super) fn struct_tail(
+        &mut self,
+        ty: Ty<'tcx>,
+        location: impl NormalizeLocation,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx();
+        if self.infcx.next_trait_solver() {
+            let body = self.body;
+            let param_env = self.param_env;
+            self.fully_perform_op(
+                location.to_locations(),
+                ConstraintCategory::Boring,
+                CustomTypeOp::new(
+                    |ocx| {
+                        let structurally_normalize = |ty| {
+                            ocx.structurally_normalize(
+                                &ObligationCause::misc(
+                                    location.to_locations().span(body),
+                                    body.source.def_id().expect_local(),
+                                ),
+                                param_env,
+                                ty,
+                            )
+                            .unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
+                        };
+
+                        let tail = tcx.struct_tail_raw(
+                            ty,
+                            structurally_normalize,
+                            || {},
+                        );
+
+                        Ok(tail)
+                    },
+                    "normalizing struct tail",
+                ),
+            )
+            .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
+        } else {
+            let mut normalize = |ty| self.normalize(ty, location);
+            let tail = tcx.struct_tail_raw(ty, &mut normalize, || {});
+            normalize(tail)
+        }
+    }
+
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn ascribe_user_type(
         &mut self,
         mir_ty: Ty<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 0cb4b15b127..9876f44c002 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -14,12 +14,10 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::ScrubbedTraitError;
 
-use crate::{
-    constraints::OutlivesConstraint,
-    region_infer::TypeTest,
-    type_check::{Locations, MirTypeckRegionConstraints},
-    universal_regions::UniversalRegions,
-};
+use crate::constraints::OutlivesConstraint;
+use crate::region_infer::TypeTest;
+use crate::type_check::{Locations, MirTypeckRegionConstraints};
+use crate::universal_regions::UniversalRegions;
 
 pub(crate) struct ConstraintConversion<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index e4c2e0fced7..b7fb9964ce7 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -1,11 +1,12 @@
+use std::rc::Rc;
+
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
 use rustc_hir::def::DefKind;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::outlives;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
 use rustc_infer::infer::region_constraints::GenericKind;
-use rustc_infer::infer::InferCtxt;
+use rustc_infer::infer::{outlives, InferCtxt};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::traits::ObligationCause;
@@ -14,14 +15,10 @@ use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::solve::deeply_normalize;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
-use std::rc::Rc;
 use type_op::TypeOpOutput;
 
-use crate::{
-    type_check::constraint_conversion,
-    type_check::{Locations, MirTypeckRegionConstraints},
-    universal_regions::UniversalRegions,
-};
+use crate::type_check::{constraint_conversion, Locations, MirTypeckRegionConstraints};
+use crate::universal_regions::UniversalRegions;
 
 #[derive(Debug)]
 pub(crate) struct UniversalRegionRelations<'tcx> {
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 741ec05dc9a..ba6030bdff7 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -16,11 +16,10 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 
+use super::{Locations, TypeChecker};
 use crate::renumber::RegionCtxt;
 use crate::universal_regions::{DefiningTy, UniversalRegions};
 
-use super::{Locations, TypeChecker};
-
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// Check explicit closure signature annotation,
     /// e.g., `|x: FxIndexMap<_, &'static u32>| ...`.
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 6d6425b5f19..a320add0636 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -1,3 +1,5 @@
+use std::rc::Rc;
+
 use itertools::{Either, Itertools};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::visit::{TyContext, Visitor};
@@ -9,14 +11,11 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_mir_dataflow::ResultsCursor;
-use std::rc::Rc;
-
-use crate::{
-    constraints::OutlivesConstraintSet, region_infer::values::LivenessValues,
-    universal_regions::UniversalRegions,
-};
 
 use super::TypeChecker;
+use crate::constraints::OutlivesConstraintSet;
+use crate::region_infer::values::LivenessValues;
+use crate::universal_regions::UniversalRegions;
 
 mod local_use_map;
 mod polonius;
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index a009e28a0dd..8c13b166c05 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -1,11 +1,11 @@
-use crate::def_use::{self, DefUse};
-use crate::location::{LocationIndex, LocationTable};
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location, Place};
 use rustc_middle::ty::GenericArg;
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 
 use super::TypeChecker;
+use crate::def_use::{self, DefUse};
+use crate::location::{LocationIndex, LocationTable};
 
 type VarPointRelation = Vec<(Local, LocationIndex)>;
 type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index eb86c8d06f1..f0c521cdcfc 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,3 +1,5 @@
+use std::rc::Rc;
+
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_index::bit_set::BitSet;
 use rustc_index::interval::IntervalSet;
@@ -6,24 +8,19 @@ use rustc_infer::infer::outlives::for_liveness;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
 use rustc_middle::traits::query::DropckOutlivesResult;
 use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
 use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
+use rustc_mir_dataflow::ResultsCursor;
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
-use std::rc::Rc;
-
-use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
-use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
-use rustc_mir_dataflow::ResultsCursor;
 
 use crate::location::RichLocation;
-use crate::{
-    region_infer::values::{self, LiveLoans},
-    type_check::liveness::local_use_map::LocalUseMap,
-    type_check::liveness::polonius,
-    type_check::NormalizeLocation,
-    type_check::TypeChecker,
-};
+use crate::region_infer::values::{self, LiveLoans};
+use crate::type_check::liveness::local_use_map::LocalUseMap;
+use crate::type_check::liveness::polonius;
+use crate::type_check::{NormalizeLocation, TypeChecker};
 
 /// This is the heart of the liveness computation. For each variable X
 /// that requires a liveness computation, it walks over all the uses
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index db4b5209145..6bab0f33c19 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -4,7 +4,6 @@ use std::rc::Rc;
 use std::{fmt, iter, mem};
 
 use either::Either;
-
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::ErrorGuaranteed;
@@ -28,44 +27,38 @@ use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
-    Dynamic, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType,
-    UserTypeAnnotationIndex,
+    Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserArgs,
+    UserType, UserTypeAnnotationIndex,
 };
-use rustc_middle::ty::{GenericArgsRef, UserArgs};
 use rustc_middle::{bug, span_bug};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::points::DenseLocationMap;
+use rustc_mir_dataflow::ResultsCursor;
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
-use rustc_span::Span;
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
-use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
-use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
+use rustc_trait_selection::traits::query::type_op::custom::{
+    scrape_region_constraints, CustomTypeOp,
+};
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
-
 use rustc_trait_selection::traits::PredicateObligation;
 
-use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
-use rustc_mir_dataflow::move_paths::MoveData;
-use rustc_mir_dataflow::ResultsCursor;
-
+use crate::borrow_set::BorrowSet;
+use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
+use crate::diagnostics::UniverseInfo;
+use crate::facts::AllFacts;
+use crate::location::LocationTable;
+use crate::member_constraints::MemberConstraintSet;
+use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
+use crate::region_infer::TypeTest;
 use crate::renumber::RegionCtxt;
 use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
-use crate::{
-    borrow_set::BorrowSet,
-    constraints::{OutlivesConstraint, OutlivesConstraintSet},
-    diagnostics::UniverseInfo,
-    facts::AllFacts,
-    location::LocationTable,
-    member_constraints::MemberConstraintSet,
-    path_utils,
-    region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices},
-    region_infer::TypeTest,
-    type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
-    universal_regions::{DefiningTy, UniversalRegions},
-    BorrowckInferCtxt,
-};
+use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
+use crate::universal_regions::{DefiningTy, UniversalRegions};
+use crate::{path_utils, BorrowckInferCtxt};
 
 macro_rules! span_mirbug {
     ($context:expr, $elem:expr, $($message:tt)*) => ({
@@ -2336,11 +2329,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
                             (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
-                                let mut normalize = |t| self.normalize(t, location);
-                                let src_tail =
-                                    tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
-                                let dst_tail =
-                                    tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
+                                let src_tail = self.struct_tail(src.ty, location);
+                                let dst_tail = self.struct_tail(dst.ty, location);
 
                                 // This checks (lifetime part of) vtable validity for pointer casts,
                                 // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 9f5fb59e46c..1ad80cb122a 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -15,6 +15,9 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use std::cell::Cell;
+use std::iter;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Diag;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -25,13 +28,12 @@ use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_macros::extension;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::ty::{
+    self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{ErrorGuaranteed, Symbol};
-use std::cell::Cell;
-use std::iter;
 
 use crate::renumber::RegionCtxt;
 use crate::BorrowckInferCtxt;
diff --git a/compiler/rustc_borrowck/src/util/collect_writes.rs b/compiler/rustc_borrowck/src/util/collect_writes.rs
index 8d92bb35938..93c7810b545 100644
--- a/compiler/rustc_borrowck/src/util/collect_writes.rs
+++ b/compiler/rustc_borrowck/src/util/collect_writes.rs
@@ -1,5 +1,4 @@
-use rustc_middle::mir::visit::PlaceContext;
-use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
 
 pub trait FindAssignments {
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index a30ab236213..9695df9c87e 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -115,9 +115,6 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
 builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
     .suggestion = remove the value
 
-builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)`
-    .suggestion = remove the `unsafe(...)`
-
 builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
     .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
     .custom = use `std::env::var({$var_expr})` to read the variable at run time
@@ -199,6 +196,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar
 
 builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
 
+builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
+    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
+
 builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
     .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
     .suggestion = remove this option
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 4721e74b955..1df2812e0c8 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -1,14 +1,15 @@
-use crate::errors;
-use crate::util::check_builtin_macro_attribute;
-
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
-use rustc_ast::{Fn, ItemKind, Safety, Stmt, TyKind};
+use rustc_ast::{
+    self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind,
+};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::errors;
+use crate::util::check_builtin_macro_attribute;
+
 pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
     _span: Span,
@@ -79,7 +80,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
     let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
     let decl = cx.fn_decl(params, never);
     let header = FnHeader { safety: Safety::Unsafe(span), ..FnHeader::default() };
-    let sig = FnSig { decl, header, span: span };
+    let sig = FnSig { decl, header, span };
 
     let body = Some(cx.block_expr(call));
     let kind = ItemKind::Fn(Box::new(Fn {
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 62e59f1f4d4..ed54c0c8662 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,8 +1,5 @@
-use crate::errors;
-use crate::util::expr_to_spanned_string;
 use ast::token::IdentIsRaw;
 use lint::BuiltinLintDiag;
-use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
@@ -11,13 +8,15 @@ use rustc_errors::PResult;
 use rustc_expand::base::*;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_parse::parser::Parser;
-use rustc_parse_format as parse;
 use rustc_session::lint;
-use rustc_span::symbol::Ident;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ErrorGuaranteed, InnerSpan, Span};
 use rustc_target::asm::InlineAsmArch;
 use smallvec::smallvec;
+use {rustc_ast as ast, rustc_parse_format as parse};
+
+use crate::errors;
+use crate::util::expr_to_spanned_string;
 
 pub struct AsmArgs {
     pub templates: Vec<P<ast::Expr>>,
@@ -29,6 +28,29 @@ pub struct AsmArgs {
     pub options_spans: Vec<Span>,
 }
 
+/// Used for better error messages when operand types are used that are not
+/// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
+///
+/// returns
+///
+/// - `Ok(true)` if the current token matches the keyword, and was expected
+/// - `Ok(false)` if the current token does not match the keyword
+/// - `Err(_)` if the current token matches the keyword, but was not expected
+fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
+    if expect {
+        Ok(p.eat_keyword(symbol))
+    } else {
+        let span = p.token.span;
+        if p.eat_keyword_noexpect(symbol) {
+            // in gets printed as `r#in` otherwise
+            let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
+            Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
+        } else {
+            Ok(false)
+        }
+    }
+}
+
 fn parse_args<'a>(
     ecx: &ExtCtxt<'a>,
     sp: Span,
@@ -106,7 +128,7 @@ pub fn parse_asm_args<'a>(
         };
 
         let mut explicit_reg = false;
-        let op = if !is_global_asm && p.eat_keyword(kw::In) {
+        let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -114,15 +136,15 @@ pub fn parse_asm_args<'a>(
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if !is_global_asm && p.eat_keyword(sym::out) {
+        } else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if !is_global_asm && p.eat_keyword(sym::lateout) {
+        } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if !is_global_asm && p.eat_keyword(sym::inout) {
+        } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -136,7 +158,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
+        } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -150,6 +172,9 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
+        } else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
+            let block = p.parse_block()?;
+            ast::InlineAsmOperand::Label { block }
         } else if p.eat_keyword(kw::Const) {
             let anon_const = p.parse_expr_anon_const()?;
             ast::InlineAsmOperand::Const { anon_const }
@@ -165,9 +190,6 @@ pub fn parse_asm_args<'a>(
                 path: path.clone(),
             };
             ast::InlineAsmOperand::Sym { sym }
-        } else if !is_global_asm && p.eat_keyword(sym::label) {
-            let block = p.parse_block()?;
-            ast::InlineAsmOperand::Label { block }
         } else if allow_templates {
             let template = p.parse_expr()?;
             // If it can't possibly expand to a string, provide diagnostics here to include other
@@ -723,10 +745,9 @@ fn expand_preparsed_asm(
             unused_operands.push((args.operands[idx].1, msg));
         }
     }
-    match unused_operands.len() {
-        0 => {}
-        1 => {
-            let (sp, msg) = unused_operands.into_iter().next().unwrap();
+    match unused_operands[..] {
+        [] => {}
+        [(sp, msg)] => {
             ecx.dcx()
                 .struct_span_err(sp, msg)
                 .with_span_label(sp, msg)
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index c75050f2701..99f433c0851 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -1,12 +1,9 @@
 mod context;
 
-use crate::edition_panic::use_panic_2021;
-use crate::errors;
 use rustc_ast::ptr::P;
-use rustc_ast::token;
 use rustc_ast::token::Delimiter;
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
+use rustc_ast::{token, DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
@@ -15,6 +12,9 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use thin_vec::thin_vec;
 
+use crate::edition_panic::use_panic_2021;
+use crate::errors;
+
 pub(crate) fn expand_assert<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index c664891dad5..2cd5b9d68a0 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -1,17 +1,15 @@
+use rustc_ast::ptr::P;
+use rustc_ast::token::{self, Delimiter, IdentIsRaw};
+use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::{
-    ptr::P,
-    token::{self, Delimiter, IdentIsRaw},
-    tokenstream::{DelimSpan, TokenStream, TokenTree},
     BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability,
     Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::ExtCtxt;
-use rustc_span::{
-    symbol::{sym, Ident, Symbol},
-    Span,
-};
+use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
 pub(super) struct Context<'cx, 'a> {
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 827719d7944..de198115fa0 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -2,14 +2,15 @@
 //! a literal `true` or `false` based on whether the given cfg matches the
 //! current compilation environment.
 
-use crate::errors;
-use rustc_ast as ast;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_attr as attr;
 use rustc_errors::PResult;
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
+use rustc_parse::parser::attr::AllowLeadingUnsafe;
 use rustc_span::Span;
+use {rustc_ast as ast, rustc_attr as attr};
+
+use crate::errors;
 
 pub(crate) fn expand_cfg(
     cx: &mut ExtCtxt<'_>,
@@ -42,7 +43,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a,
         return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
     }
 
-    let cfg = p.parse_meta_item()?;
+    let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?;
 
     let _ = p.eat(&token::Comma);
 
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 98c0ca3a526..006b6aa823f 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -1,6 +1,5 @@
 //! Implementation of the `#[cfg_accessible(path)]` attribute macro.
 
-use crate::errors;
 use rustc_ast as ast;
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
 use rustc_feature::AttributeTemplate;
@@ -8,6 +7,8 @@ use rustc_parse::validate_attr;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
+use crate::errors;
+
 pub(crate) struct Expander;
 
 fn validate_input<'a>(ecx: &ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
@@ -46,11 +47,13 @@ impl MultiItemModifier for Expander {
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let template = AttributeTemplate { list: Some("path"), ..Default::default() };
         validate_attr::check_builtin_meta_item(
+            &ecx.ecfg.features,
             &ecx.sess.psess,
             meta_item,
             ast::AttrStyle::Outer,
             sym::cfg_accessible,
             template,
+            true,
         );
 
         let Some(path) = validate_input(ecx, meta_item) else {
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index b3d252e06a5..4b05c144d37 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -1,13 +1,10 @@
-use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
-
 use core::ops::ControlFlow;
+
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{AssocCtxt, Visitor};
-use rustc_ast::NodeId;
-use rustc_ast::{mut_visit, visit};
-use rustc_ast::{Attribute, HasAttrs, HasTokens};
+use rustc_ast::{mut_visit, visit, Attribute, HasAttrs, HasTokens, NodeId};
 use rustc_errors::PResult;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_expand::config::StripUnconfigured;
@@ -20,6 +17,8 @@ use rustc_span::Span;
 use smallvec::SmallVec;
 use tracing::instrument;
 
+use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
+
 pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
     _span: Span,
@@ -203,7 +202,7 @@ impl CfgEval<'_> {
         }
 
         // Now that we have our re-parsed `AttrTokenStream`, recursively configuring
-        // our attribute target will correctly the tokens as well.
+        // our attribute target will correctly configure the tokens as well.
         flat_map_annotatable(self, annotatable)
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index bffd5672b9b..66fa74da60d 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -1,14 +1,14 @@
 //! Attributes injected into the crate root from command line using `-Z crate-attr`.
 
-use crate::errors;
 use rustc_ast::attr::mk_attr;
-use rustc_ast::token;
-use rustc_ast::{self as ast, AttrItem, AttrStyle};
+use rustc_ast::{self as ast, token, AttrItem, AttrStyle};
 use rustc_parse::parser::ForceCollect;
 use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::parse::ParseSess;
 use rustc_span::FileName;
 
+use crate::errors;
+
 pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
     for raw_attr in attrs {
         let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs
index a08e8b2819b..7fc4b437c1d 100644
--- a/compiler/rustc_builtin_macros/src/compile_error.rs
+++ b/compiler/rustc_builtin_macros/src/compile_error.rs
@@ -1,10 +1,11 @@
 // The compiler code necessary to support the compile_error! extension.
 
-use crate::util::get_single_str_from_tts;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::Span;
 
+use crate::util::get_single_str_from_tts;
+
 pub(crate) fn expand_compile_error<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index 15af79ef67d..a28801f66dd 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -1,11 +1,12 @@
-use crate::errors;
-use crate::util::get_exprs_from_tts;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{ExprKind, LitKind, UnOp};
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_session::errors::report_lit_error;
 use rustc_span::symbol::Symbol;
 
+use crate::errors;
+use crate::util::get_exprs_from_tts;
+
 pub(crate) fn expand_concat(
     cx: &mut ExtCtxt<'_>,
     sp: rustc_span::Span,
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index 3130870df41..196bf906dc0 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -1,10 +1,13 @@
-use crate::errors;
-use crate::util::get_exprs_from_tts;
-use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy};
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{token, ExprKind, LitIntType, LitKind, UintTy};
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_session::errors::report_lit_error;
 use rustc_span::{ErrorGuaranteed, Span};
 
+use crate::errors;
+use crate::util::get_exprs_from_tts;
+
 /// Emits errors for literal expressions that are invalid inside and outside of an array.
 fn invalid_type_err(
     cx: &ExtCtxt<'_>,
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index b5cbfdf0ec6..57bddf0ab60 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -1,8 +1,5 @@
-use crate::cfg_eval::cfg_eval;
-use crate::errors;
-
 use rustc_ast as ast;
-use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind};
+use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
 use rustc_expand::base::{
     Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
 };
@@ -12,6 +9,9 @@ use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{ErrorGuaranteed, Span};
 
+use crate::cfg_eval::cfg_eval;
+use crate::errors;
+
 pub(crate) struct Expander {
     pub is_const: bool,
 }
@@ -38,11 +38,13 @@ impl MultiItemModifier for Expander {
                 let template =
                     AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
                 validate_attr::check_builtin_meta_item(
+                    features,
                     &sess.psess,
                     meta_item,
                     ast::AttrStyle::Outer,
                     sym::derive,
                     template,
+                    true,
                 );
 
                 let mut resolutions = match &meta_item.kind {
@@ -60,7 +62,6 @@ impl MultiItemModifier for Expander {
                                 // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
                                 // paths.
                                 report_path_args(sess, meta);
-                                report_unsafe_args(sess, meta);
                                 meta.path.clone()
                             })
                             .map(|path| DeriveResolution {
@@ -160,13 +161,3 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
         }
     }
 }
-
-fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) {
-    match meta.unsafety {
-        Safety::Unsafe(span) => {
-            sess.dcx().emit_err(errors::DeriveUnsafePath { span });
-        }
-        Safety::Default => {}
-        Safety::Safe(_) => unreachable!(),
-    }
-}
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index f6b54335829..a98e9c6d1c7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -1,10 +1,10 @@
-use crate::deriving::generic::*;
-use crate::deriving::path_std;
-
 use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::Span;
 
+use crate::deriving::generic::*;
+use crate::deriving::path_std;
+
 pub(crate) fn expand_deriving_copy(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index abcb402a46f..22beca4ea9a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -1,6 +1,3 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::path_std;
 use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -8,6 +5,10 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::path_std;
+
 pub(crate) fn expand_deriving_clone(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 53a15131605..a5e12174796 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -1,7 +1,3 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::path_std;
-
 use rustc_ast::{self as ast, MetaItem};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -9,6 +5,10 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::path_std;
+
 pub(crate) fn expand_deriving_eq(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 8470d466a23..705c41175e7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -1,12 +1,13 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::path_std;
 use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::path_std;
+
 pub(crate) fn expand_deriving_ord(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index a6457f4a433..f6299589e0f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -1,6 +1,3 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::{path_local, path_std};
 use rustc_ast::ptr::P;
 use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -8,6 +5,10 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::{path_local, path_std};
+
 pub(crate) fn expand_deriving_partial_eq(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 006e5a3d268..a51f98f5396 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -1,12 +1,13 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::{path_std, pathvec_std};
 use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::{path_std, pathvec_std};
+
 pub(crate) fn expand_deriving_partial_ord(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 57ec0435e3e..755e6ee0d3e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -1,13 +1,13 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::path_std;
-
 use rustc_ast::{self as ast, EnumDef, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::path_std;
+
 pub(crate) fn expand_deriving_debug(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index e9851c87aea..89300a36d1b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -1,8 +1,5 @@
 //! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more.
 
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::pathvec_std;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, Expr, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -10,6 +7,10 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::pathvec_std;
+
 pub(crate) fn expand_deriving_rustc_decodable(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 7a65ed97f00..afc55ddd230 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -1,17 +1,18 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::errors;
 use core::ops::ControlFlow;
+
 use rustc_ast as ast;
 use rustc_ast::visit::visit_opt;
 use rustc_ast::{attr, EnumDef, VariantData};
 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
-use rustc_span::symbol::Ident;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{ErrorGuaranteed, Span};
 use smallvec::SmallVec;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::errors;
+
 pub(crate) fn expand_deriving_default(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 3bd74d8d019..9c26d05f811 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -85,15 +85,16 @@
 //! }
 //! ```
 
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::pathvec_std;
 use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::pathvec_std;
+
 pub(crate) fn expand_deriving_rustc_encodable(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index ba289f9552e..c90a9164886 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -174,26 +174,25 @@
 //! )
 //! ```
 
-pub(crate) use StaticFields::*;
-pub(crate) use SubstructureFields::*;
+use std::cell::RefCell;
+use std::ops::Not;
+use std::{iter, vec};
 
-use crate::{deriving, errors};
 use rustc_ast::ptr::P;
 use rustc_ast::{
     self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
-    Mutability, PatKind, TyKind, VariantData,
+    Mutability, PatKind, VariantData,
 };
 use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use std::cell::RefCell;
-use std::iter;
-use std::ops::Not;
-use std::vec;
 use thin_vec::{thin_vec, ThinVec};
 use ty::{Bounds, Path, Ref, Self_, Ty};
+pub(crate) use StaticFields::*;
+pub(crate) use SubstructureFields::*;
+
+use crate::{deriving, errors};
 
 pub(crate) mod ty;
 
@@ -379,8 +378,8 @@ impl BlockOrExpr {
                 None => cx.expr_block(cx.block(span, ThinVec::new())),
                 Some(expr) => expr,
             }
-        } else if self.0.len() == 1
-            && let ast::StmtKind::Expr(expr) = &self.0[0].kind
+        } else if let [stmt] = self.0.as_slice()
+            && let ast::StmtKind::Expr(expr) = &stmt.kind
             && self.1.is_none()
         {
             // There's only a single statement expression. Pull it out.
@@ -1274,7 +1273,7 @@ impl<'a> MethodDef<'a> {
                     }
                     FieldlessVariantsStrategy::Default => (),
                 }
-            } else if variants.len() == 1 {
+            } else if let [variant] = variants.as_slice() {
                 // If there is a single variant, we don't need an operation on
                 // the discriminant(s). Just use the most degenerate result.
                 return self.call_substructure_method(
@@ -1282,7 +1281,7 @@ impl<'a> MethodDef<'a> {
                     trait_,
                     type_ident,
                     nonselflike_args,
-                    &EnumMatching(0, &variants[0], Vec::new()),
+                    &EnumMatching(0, variant, Vec::new()),
                 );
             }
         }
@@ -1599,52 +1598,11 @@ impl<'a> TraitDef<'a> {
                         ),
                     );
                     if is_packed {
-                        // In general, fields in packed structs are copied via a
-                        // block, e.g. `&{self.0}`. The two exceptions are `[u8]`
-                        // and `str` fields, which cannot be copied and also never
-                        // cause unaligned references. These exceptions are allowed
-                        // to handle the `FlexZeroSlice` type in the `zerovec`
-                        // crate within `icu4x-0.9.0`.
-                        //
-                        // Once use of `icu4x-0.9.0` has dropped sufficiently, this
-                        // exception should be removed.
-                        let is_simple_path = |ty: &P<ast::Ty>, sym| {
-                            if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind
-                                && let [seg] = segments.as_slice()
-                                && seg.ident.name == sym
-                                && seg.args.is_none()
-                            {
-                                true
-                            } else {
-                                false
-                            }
-                        };
-
-                        let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind
-                            && is_simple_path(ty, sym::u8)
-                        {
-                            Some("byte")
-                        } else if is_simple_path(&struct_field.ty, sym::str) {
-                            Some("string")
-                        } else {
-                            None
-                        };
-
-                        if let Some(ty) = exception {
-                            cx.sess.psess.buffer_lint(
-                                BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
-                                sp,
-                                ast::CRATE_NODE_ID,
-                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
-                                    ty: ty.to_string(),
-                                },
-                            );
-                        } else {
-                            // Wrap the expression in `{...}`, causing a copy.
-                            field_expr = cx.expr_block(
-                                cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]),
-                            );
-                        }
+                        // Fields in packed structs are wrapped in a block, e.g. `&{self.0}`,
+                        // causing a copy instead of a (potentially misaligned) reference.
+                        field_expr = cx.expr_block(
+                            cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]),
+                        );
                     }
                     cx.expr_addr_of(sp, field_expr)
                 })
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index f01d586033e..747da2ee43b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -1,8 +1,6 @@
 //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
 //! when specifying impls to be derived.
 
-pub(crate) use Ty::*;
-
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
 use rustc_expand::base::ExtCtxt;
@@ -10,6 +8,7 @@ use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use thin_vec::ThinVec;
+pub(crate) use Ty::*;
 
 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
 /// for type parameters.
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index dcd92819865..4fa6686b7b3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -1,12 +1,13 @@
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::{path_std, pathvec_std};
 use rustc_ast::{MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
+use crate::deriving::generic::ty::*;
+use crate::deriving::generic::*;
+use crate::deriving::{path_std, pathvec_std};
+
 pub(crate) fn expand_deriving_hash(
     cx: &ExtCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
index bbc7cd39627..7eb1f17a59c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
@@ -1,14 +1,16 @@
-use std::mem::swap;
-
+use ast::ptr::P;
 use ast::HasAttrs;
+use rustc_ast::mut_visit::MutVisitor;
+use rustc_ast::visit::BoundKind;
 use rustc_ast::{
     self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem,
-    TraitBoundModifiers, VariantData,
+    TraitBoundModifiers, VariantData, WherePredicate,
 };
 use rustc_attr as attr;
+use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use smallvec::{smallvec, SmallVec};
 use thin_vec::{thin_vec, ThinVec};
 
@@ -141,33 +143,237 @@ pub fn expand_deriving_smart_ptr(
     alt_self_params[pointee_param_idx] = GenericArg::Type(s_ty.clone());
     let alt_self_type = cx.ty_path(cx.path_all(span, false, vec![name_ident], alt_self_params));
 
+    // # Add `Unsize<__S>` bound to `#[pointee]` at the generic parameter location
+    //
     // Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
     let mut impl_generics = generics.clone();
+    let pointee_ty_ident = generics.params[pointee_param_idx].ident;
+    let mut self_bounds;
     {
-        let p = &mut impl_generics.params[pointee_param_idx];
+        let pointee = &mut impl_generics.params[pointee_param_idx];
+        self_bounds = pointee.bounds.clone();
+        if !contains_maybe_sized_bound(&self_bounds)
+            && !contains_maybe_sized_bound_on_pointee(
+                &generics.where_clause.predicates,
+                pointee_ty_ident.name,
+            )
+        {
+            cx.dcx()
+                .struct_span_err(
+                    pointee_ty_ident.span,
+                    format!(
+                        "`derive(SmartPointer)` requires {} to be marked `?Sized`",
+                        pointee_ty_ident.name
+                    ),
+                )
+                .emit();
+            return;
+        }
         let arg = GenericArg::Type(s_ty.clone());
         let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]);
-        p.bounds.push(cx.trait_bound(unsize, false));
-        let mut attrs = thin_vec![];
-        swap(&mut p.attrs, &mut attrs);
-        p.attrs = attrs.into_iter().filter(|attr| !attr.has_name(sym::pointee)).collect();
+        pointee.bounds.push(cx.trait_bound(unsize, false));
+        // Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)`
+        pointee.attrs.retain(|attr| !attr.has_name(sym::pointee));
+    }
+
+    // # Rewrite generic parameter bounds
+    // For each bound `U: ..` in `struct<U: ..>`, make a new bound with `__S` in place of `#[pointee]`
+    // Example:
+    // ```
+    // struct<
+    //     U: Trait<T>,
+    //     #[pointee] T: Trait<T> + ?Sized,
+    //     V: Trait<T>> ...
+    // ```
+    // ... generates this `impl` generic parameters
+    // ```
+    // impl<
+    //     U: Trait<T> + Trait<__S>,
+    //     T: Trait<T> + ?Sized + Unsize<__S>, // (**)
+    //     __S: Trait<__S> + ?Sized, // (*)
+    //     V: Trait<T> + Trait<__S>> ...
+    // ```
+    // The new bound marked with (*) has to be done separately.
+    // See next section
+    for (idx, (params, orig_params)) in
+        impl_generics.params.iter_mut().zip(&generics.params).enumerate()
+    {
+        // Default type parameters are rejected for `impl` block.
+        // We should drop them now.
+        match &mut params.kind {
+            ast::GenericParamKind::Const { default, .. } => *default = None,
+            ast::GenericParamKind::Type { default } => *default = None,
+            ast::GenericParamKind::Lifetime => {}
+        }
+        // We CANNOT rewrite `#[pointee]` type parameter bounds.
+        // This has been set in stone. (**)
+        // So we skip over it.
+        // Otherwise, we push extra bounds involving `__S`.
+        if idx != pointee_param_idx {
+            for bound in &orig_params.bounds {
+                let mut bound = bound.clone();
+                let mut substitution = TypeSubstitution {
+                    from_name: pointee_ty_ident.name,
+                    to_ty: &s_ty,
+                    rewritten: false,
+                };
+                substitution.visit_param_bound(&mut bound, BoundKind::Bound);
+                if substitution.rewritten {
+                    // We found use of `#[pointee]` somewhere,
+                    // so we make a new bound using `__S` in place of `#[pointee]`
+                    params.bounds.push(bound);
+                }
+            }
+        }
+    }
+
+    // # Insert `__S` type parameter
+    //
+    // We now insert `__S` with the missing bounds marked with (*) above.
+    // We should also write the bounds from `#[pointee]` to `__S` as required by `Unsize<__S>`.
+    {
+        let mut substitution =
+            TypeSubstitution { from_name: pointee_ty_ident.name, to_ty: &s_ty, rewritten: false };
+        for bound in &mut self_bounds {
+            substitution.visit_param_bound(bound, BoundKind::Bound);
+        }
+    }
+
+    // # Rewrite `where` clauses
+    //
+    // Move on to `where` clauses.
+    // Example:
+    // ```
+    // struct MyPointer<#[pointee] T, ..>
+    // where
+    //   U: Trait<V> + Trait<T>,
+    //   Companion<T>: Trait<T>,
+    //   T: Trait<T> + ?Sized,
+    // { .. }
+    // ```
+    // ... will have a impl prelude like so
+    // ```
+    // impl<..> ..
+    // where
+    //   U: Trait<V> + Trait<T>,
+    //   U: Trait<__S>,
+    //   Companion<T>: Trait<T>,
+    //   Companion<__S>: Trait<__S>,
+    //   T: Trait<T> + ?Sized,
+    //   __S: Trait<__S> + ?Sized,
+    // ```
+    //
+    // We should also write a few new `where` bounds from `#[pointee] T` to `__S`
+    // as well as any bound that indirectly involves the `#[pointee] T` type.
+    for bound in &generics.where_clause.predicates {
+        if let ast::WherePredicate::BoundPredicate(bound) = bound {
+            let mut substitution = TypeSubstitution {
+                from_name: pointee_ty_ident.name,
+                to_ty: &s_ty,
+                rewritten: false,
+            };
+            let mut predicate = ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                span: bound.span,
+                bound_generic_params: bound.bound_generic_params.clone(),
+                bounded_ty: bound.bounded_ty.clone(),
+                bounds: bound.bounds.clone(),
+            });
+            substitution.visit_where_predicate(&mut predicate);
+            if substitution.rewritten {
+                impl_generics.where_clause.predicates.push(predicate);
+            }
+        }
     }
 
-    // Add the `__S: ?Sized` extra parameter to the impl block.
-    let sized = cx.path_global(span, path!(span, core::marker::Sized));
-    let bound = GenericBound::Trait(
-        cx.poly_trait_ref(span, sized),
-        TraitBoundModifiers {
-            polarity: ast::BoundPolarity::Maybe(span),
-            constness: ast::BoundConstness::Never,
-            asyncness: ast::BoundAsyncness::Normal,
-        },
-    );
-    let extra_param = cx.typaram(span, Ident::new(sym::__S, span), vec![bound], None);
-    impl_generics.params.push(extra_param);
+    let extra_param = cx.typaram(span, Ident::new(sym::__S, span), self_bounds, None);
+    impl_generics.params.insert(pointee_param_idx + 1, extra_param);
 
     // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`.
     let gen_args = vec![GenericArg::Type(alt_self_type.clone())];
     add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone());
     add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone());
 }
+
+fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
+    for bound in predicates {
+        if let ast::WherePredicate::BoundPredicate(bound) = bound
+            && bound.bounded_ty.kind.is_simple_path().is_some_and(|name| name == pointee)
+        {
+            for bound in &bound.bounds {
+                if is_maybe_sized_bound(bound) {
+                    return true;
+                }
+            }
+        }
+    }
+    false
+}
+
+fn is_maybe_sized_bound(bound: &GenericBound) -> bool {
+    if let GenericBound::Trait(
+        trait_ref,
+        TraitBoundModifiers { polarity: ast::BoundPolarity::Maybe(_), .. },
+    ) = bound
+    {
+        is_sized_marker(&trait_ref.trait_ref.path)
+    } else {
+        false
+    }
+}
+
+fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool {
+    bounds.iter().any(is_maybe_sized_bound)
+}
+
+fn path_segment_is_exact_match(path_segments: &[ast::PathSegment], syms: &[Symbol]) -> bool {
+    path_segments.iter().zip(syms).all(|(segment, &symbol)| segment.ident.name == symbol)
+}
+
+fn is_sized_marker(path: &ast::Path) -> bool {
+    const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized];
+    const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized];
+    if path.segments.len() == 4 && path.is_global() {
+        path_segment_is_exact_match(&path.segments[1..], &CORE_UNSIZE)
+            || path_segment_is_exact_match(&path.segments[1..], &STD_UNSIZE)
+    } else if path.segments.len() == 3 {
+        path_segment_is_exact_match(&path.segments, &CORE_UNSIZE)
+            || path_segment_is_exact_match(&path.segments, &STD_UNSIZE)
+    } else {
+        *path == sym::Sized
+    }
+}
+
+struct TypeSubstitution<'a> {
+    from_name: Symbol,
+    to_ty: &'a ast::Ty,
+    rewritten: bool,
+}
+
+impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
+    fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
+        if let Some(name) = ty.kind.is_simple_path()
+            && name == self.from_name
+        {
+            **ty = self.to_ty.clone();
+            self.rewritten = true;
+        } else {
+            ast::mut_visit::walk_ty(self, ty);
+        }
+    }
+
+    fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) {
+        match where_predicate {
+            rustc_ast::WherePredicate::BoundPredicate(bound) => {
+                bound
+                    .bound_generic_params
+                    .flat_map_in_place(|param| self.flat_map_generic_param(param));
+                self.visit_ty(&mut bound.bounded_ty);
+                for bound in &mut bound.bounds {
+                    self.visit_param_bound(bound, BoundKind::Bound)
+                }
+            }
+            rustc_ast::WherePredicate::RegionPredicate(_)
+            | rustc_ast::WherePredicate::EqPredicate(_) => {}
+        }
+    }
+}
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index b03e14cf263..1a4fc65f0a8 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -3,18 +3,20 @@
 // interface.
 //
 
-use crate::errors;
-use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
+use std::env;
+use std::env::VarError;
+
 use rustc_ast::token::{self, LitKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability};
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
-use std::env;
-use std::env::VarError;
 use thin_vec::thin_vec;
 
+use crate::errors;
+use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
+
 fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
     let var = var.as_str();
     if let Some(value) = cx.sess.opts.logical_env.get(var) {
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index f17819474ad..6ca43441e05 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -1,9 +1,11 @@
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan,
-    SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic,
+    Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
+    SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_span::{symbol::Ident, Span, Symbol};
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
 #[diag(builtin_macros_requires_cfg_pattern)]
@@ -296,13 +298,6 @@ pub(crate) struct DerivePathArgsValue {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_derive_unsafe_path)]
-pub(crate) struct DeriveUnsafePath {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(builtin_macros_no_default_variant)]
 #[help]
 pub(crate) struct NoDefaultVariant {
@@ -857,6 +852,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_global_asm_unsupported_operand)]
+pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) symbol: &'a str,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_test_runner_invalid)]
 pub(crate) struct TestRunnerInvalid {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 5cb0407bd59..f99530cad18 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1,13 +1,10 @@
-use crate::errors;
-use crate::util::expr_to_spanned_string;
 use parse::Position::ArgumentNamed;
 use rustc_ast::ptr::P;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{token, StmtKind};
 use rustc_ast::{
-    Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
+    token, Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
     FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
-    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered,
+    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered, StmtKind,
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
@@ -18,6 +15,9 @@ use rustc_parse_format as parse;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span};
 
+use crate::errors;
+use crate::util::expr_to_spanned_string;
+
 // The format_args!() macro is expanded in three steps:
 //  1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
 //     but doesn't parse the template (the literal) itself.
@@ -180,8 +180,8 @@ fn make_format_args(
                     Ok((mut err, suggested)) => {
                         if !suggested {
                             if let ExprKind::Block(block, None) = &efmt.kind
-                                && block.stmts.len() == 1
-                                && let StmtKind::Expr(expr) = &block.stmts[0].kind
+                                && let [stmt] = block.stmts.as_slice()
+                                && let StmtKind::Expr(expr) = &stmt.kind
                                 && let ExprKind::Path(None, path) = &expr.kind
                                 && path.is_potential_trivial_const_arg()
                             {
@@ -196,8 +196,8 @@ fn make_format_args(
                             } else {
                                 let sugg_fmt = match args.explicit_args().len() {
                                     0 => "{}".to_string(),
-                                    _ => {
-                                        format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
+                                    count => {
+                                        format!("{}{{}}", "{} ".repeat(count))
                                     }
                                 };
                                 err.span_suggestion(
@@ -555,7 +555,7 @@ fn make_format_args(
             };
             let arg_name = args.explicit_args()[index].kind.ident().unwrap();
             ecx.buffered_early_lint.push(BufferedEarlyLint {
-                span: arg_name.span.into(),
+                span: Some(arg_name.span.into()),
                 node_id: rustc_ast::CRATE_NODE_ID,
                 lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
                 diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index bc2c6def68a..b52f606f342 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -1,7 +1,8 @@
 pub(crate) mod printf {
-    use super::strcursor::StrCursor as Cur;
     use rustc_span::InnerSpan;
 
+    use super::strcursor::StrCursor as Cur;
+
     /// Represents a single `printf`-style substitution.
     #[derive(Clone, PartialEq, Debug)]
     pub enum Substitution<'a> {
@@ -615,9 +616,10 @@ pub(crate) mod printf {
 }
 
 pub mod shell {
-    use super::strcursor::StrCursor as Cur;
     use rustc_span::InnerSpan;
 
+    use super::strcursor::StrCursor as Cur;
+
     #[derive(Clone, PartialEq, Debug)]
     pub enum Substitution<'a> {
         Ordinal(u8, (usize, usize)),
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index b44ff979303..734da318ac1 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -1,17 +1,19 @@
-use crate::util::check_builtin_macro_attribute;
-
-use crate::errors;
 use rustc_ast::expand::allocator::{
     global_fn_name, AllocatorMethod, AllocatorMethodInput, AllocatorTy, ALLOCATOR_METHODS,
 };
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{Fn, ItemKind, Mutability, Safety, Stmt, Ty, TyKind};
+use rustc_ast::{
+    self as ast, AttrVec, Expr, Fn, FnHeader, FnSig, Generics, ItemKind, Mutability, Param, Safety,
+    Stmt, StmtKind, Ty, TyKind,
+};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::errors;
+use crate::util::check_builtin_macro_attribute;
+
 pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
     _span: Span,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index c77ff9eb13c..a9ba7334d93 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -5,7 +5,6 @@
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
@@ -21,11 +20,12 @@
 
 extern crate proc_macro;
 
-use crate::deriving::*;
 use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::symbol::sym;
 
+use crate::deriving::*;
+
 mod alloc_error_handler;
 mod assert;
 mod cfg;
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
index 31f5656df13..869d203f68e 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -1,4 +1,6 @@
-use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty};
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{ast, Pat, Ty};
 use rustc_errors::PResult;
 use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::{sym, Span};
@@ -22,7 +24,7 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
     let mut parser = cx.new_parser_from_tts(stream);
 
     let ty = parser.parse_ty()?;
-    parser.eat_keyword(sym::is);
+    parser.expect_keyword(sym::is)?;
     let pat = parser.parse_pat_no_top_alt(None, None)?;
 
     Ok((ty, pat))
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index a8a595ea579..6b2b2b90457 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -1,4 +1,5 @@
-use crate::errors;
+use std::mem;
+
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast::{self as ast, attr, NodeId};
@@ -13,9 +14,10 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::smallvec;
-use std::mem;
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::errors;
+
 struct ProcMacroDerive {
     id: NodeId,
     trait_name: Symbol,
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 44db12cf695..9554d97829e 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -1,7 +1,6 @@
-use crate::errors;
-use crate::util::{
-    check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
-};
+use std::path::{Path, PathBuf};
+use std::rc::Rc;
+
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
@@ -20,8 +19,11 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Pos, Span};
 use smallvec::SmallVec;
-use std::path::{Path, PathBuf};
-use std::rc::Rc;
+
+use crate::errors;
+use crate::util::{
+    check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
+};
 
 // These macros all relate to the file system; they either return
 // the column/row/filename of the expression, or they include
@@ -71,7 +73,8 @@ pub(crate) fn expand_file(
     let topmost = cx.expansion_cause().unwrap_or(sp);
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
-    use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+    use rustc_session::config::RemapPathScopeComponents;
+    use rustc_session::RemapFileNameExt;
     ExpandResult::Ready(MacEager::expr(cx.expr_str(
         topmost,
         Symbol::intern(
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index bb00c8de1b8..1b76a5f3234 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -1,8 +1,9 @@
 //! The expansion from a test function to the appropriate test struct for libtest
 //! Ideally, this code would be in libtest but for efficiency and error messages it lives here.
 
-use crate::errors;
-use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
+use std::assert_matches::assert_matches;
+use std::iter;
+
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, attr, GenericParamKind};
 use rustc_ast_pretty::pprust;
@@ -10,11 +11,12 @@ use rustc_errors::{Applicability, Diag, Level};
 use rustc_expand::base::*;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
-use std::assert_matches::assert_matches;
-use std::iter;
 use thin_vec::{thin_vec, ThinVec};
 use tracing::debug;
 
+use crate::errors;
+use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
+
 /// #[test_case] is used by custom test authors to mark tests
 /// When building for test, it needs to make the item public and gensym the name
 /// Otherwise, we'll omit the item. This behavior means that any item annotated
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index bbafb0ac299..a9e44345811 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -1,5 +1,7 @@
 // Code that generates a test runner to run all the tests in a crate
 
+use std::{iter, mem};
+
 use rustc_ast as ast;
 use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::*;
@@ -21,8 +23,6 @@ use smallvec::{smallvec, SmallVec};
 use thin_vec::{thin_vec, ThinVec};
 use tracing::debug;
 
-use std::{iter, mem};
-
 use crate::errors;
 
 #[derive(Clone)]
diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs
index 4833ec32f76..bd9ebc355e1 100644
--- a/compiler/rustc_builtin_macros/src/trace_macros.rs
+++ b/compiler/rustc_builtin_macros/src/trace_macros.rs
@@ -1,9 +1,10 @@
-use crate::errors;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 
+use crate::errors;
+
 pub(crate) fn expand_trace_macros(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index fabcb6a4b70..73cc8ff547d 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -1,24 +1,29 @@
-use crate::errors;
+use rustc_ast::ptr::P;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{self as ast, attr, ptr::P, token, AttrStyle, Attribute, MetaItem};
+use rustc_ast::{self as ast, attr, token, AttrStyle, Attribute, MetaItem};
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
 use rustc_expand::expand::AstFragment;
 use rustc_feature::AttributeTemplate;
-use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag};
+use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::{parser, validate_attr};
 use rustc_session::errors::report_lit_error;
 use rustc_span::{BytePos, Span, Symbol};
 
+use crate::errors;
+
 pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
     // All the built-in macro attributes are "words" at the moment.
     let template = AttributeTemplate { word: true, ..Default::default() };
     validate_attr::check_builtin_meta_item(
+        &ecx.ecfg.features,
         &ecx.sess.psess,
         meta_item,
         AttrStyle::Outer,
         name,
         template,
+        true,
     );
 }
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
index 1ed6f8fc359..30dc5cb1615 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
@@ -2,13 +2,14 @@ name: Abi-cafe
 
 on:
   - push
+  - pull_request
 
 permissions: {}
 
 jobs:
   abi_cafe:
     runs-on: ${{ matrix.os }}
-    timeout-minutes: 60
+    timeout-minutes: 30
     concurrency:
       group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}-${{ matrix.env.TARGET_TRIPLE }}
       cancel-in-progress: true
@@ -27,12 +28,16 @@ jobs:
           - os: macos-latest
             env:
               TARGET_TRIPLE: x86_64-apple-darwin
-          - os: windows-latest
+          - os: macos-latest
             env:
-              TARGET_TRIPLE: x86_64-pc-windows-msvc
+              TARGET_TRIPLE: aarch64-apple-darwin
           - os: windows-latest
             env:
-              TARGET_TRIPLE: x86_64-pc-windows-gnu
+              TARGET_TRIPLE: x86_64-pc-windows-msvc
+          # FIXME Currently hangs. Re-enable once this is fixed or abi-cafe adds a timeout.
+          #- os: windows-latest
+          #  env:
+          #    TARGET_TRIPLE: x86_64-pc-windows-gnu
 
     steps:
     - uses: actions/checkout@v4
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
index b4f8ce0f532..27c95572ef8 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
@@ -13,7 +13,6 @@ jobs:
       - uses: actions/checkout@v4
       - run: |
           sed -i 's/components.*/components = []/' rust-toolchain
-          echo 'profile = "minimal"' >> rust-toolchain
       - uses: rustsec/audit-check@v1.4.1
         with:
           token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index a2ae3d63fb9..896a5c34c3e 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -29,7 +29,6 @@ jobs:
     - name: Avoid installing rustc-dev
       run: |
         sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain
-        echo 'profile = "minimal"' >> rust-toolchain
         rustfmt -v
 
     - name: Rustfmt
diff --git a/compiler/rustc_codegen_cranelift/.zed/settings.json b/compiler/rustc_codegen_cranelift/.zed/settings.json
new file mode 100644
index 00000000000..e93bed36949
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.zed/settings.json
@@ -0,0 +1,68 @@
+{
+  "format_on_save": "on",
+  "lsp": {
+    "rust-analyzer": {
+      "initialization_options": {
+        "diagnostics": {
+          // in case rustc.source is disabled for performance reasons; disable the errors about this
+          "disabled": ["unresolved-extern-crate", "unresolved-macro-call"]
+        },
+        "rustc": {
+          "source": "discover"
+        },
+        "imports": {
+          "granularity": {
+            "enforce": true,
+            "group": "module"
+          },
+          "prefix": "crate"
+        },
+        "cargo": {
+          "features": ["unstable-features"]
+        },
+        "linkedProjects": [
+          "./Cargo.toml",
+          "./build_system/Cargo.toml",
+          {
+            "crates": [
+              {
+                "root_module": "./example/mini_core.rs",
+                "edition": "2018",
+                "deps": [],
+                "cfg": []
+              },
+              {
+                "root_module": "./example/mini_core_hello_world.rs",
+                "edition": "2018",
+                "deps": [
+                  {
+                    "crate": 0,
+                    "name": "mini_core"
+                  }
+                ],
+                "cfg": []
+              },
+              {
+                "root_module": "./example/mod_bench.rs",
+                "edition": "2018",
+                "deps": [],
+                "cfg": []
+              }
+            ]
+          },
+          {
+            "sysroot_src": "./build/stdlib/library",
+            "crates": [
+              {
+                "root_module": "./example/std_example.rs",
+                "edition": "2015",
+                "deps": [],
+                "cfg": []
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index efec5db836b..02d4d98dc42 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -46,21 +46,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b6b33d7e757a887989eb18b35712b2a67d96171ec3149d1bfb657b29b7b367c"
+checksum = "effa84ab2023f7138045ece6b326588c17447ca22e66db71ec15cb0a6c0c4ad2"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
+name = "cranelift-bitset"
+version = "0.110.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38a1dfc50dca188a15d938867c4400589530bcb0138f7022aae6d059d1d8c309"
+
+[[package]]
 name = "cranelift-codegen"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9acf15cb22be42d07c3b57d7856329cb228b7315d385346149df2566ad5e4aa"
+checksum = "821c20c639350158ecca928dc2a244d0d1c9cef2377a378fc62a445a286eb1ca"
 dependencies = [
  "bumpalo",
  "cranelift-bforest",
+ "cranelift-bitset",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
  "cranelift-control",
@@ -77,39 +84,42 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e934d301392b73b3f8b0540391fb82465a0f179a3cee7c726482ac4727efcc97"
+checksum = "064473f2fd59b44fa2c9aaa60de1f9c44db5e13521e28bc85d2b92ee535ef625"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb2a2566b3d54b854dfb288b3b187f6d3d17d6f762c92898207eba302931da"
+checksum = "d0f39b9ebfd2febdc2acfb9a0fca110665bcd5a6839502576307735ed07b2177"
 
 [[package]]
 name = "cranelift-control"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0100f33b704cdacd01ad66ff41f8c5030d57cbff078e2a4e49ab1822591299fa"
+checksum = "94e125c189c3a1ca8dfe209fc6f46edba058a6d24e0b92aff69459a15f4711e7"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8cfdc315e5d18997093e040a8d234bea1ac1e118a716d3e30f40d449e78207b"
+checksum = "ea62eb109baec2247e1a6fa7b74c0f584b1e76e289cfd7017385b4b031fc8450"
+dependencies = [
+ "cranelift-bitset",
+]
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f74b84f16af2e982b0c0c72233503d9d55cbfe3865dbe807ca28dc6642a28b5"
+checksum = "722b089357aacb6c7528b2e59a5fe00917d61ce63448b25a3e477a5b7819fac8"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -119,15 +129,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adf306d3dde705fb94bd48082f01d38c4ededc74293a4c007805f610bf08bc6e"
+checksum = "c4b5005a48288e7fc2a2991a377831c534e26929b063c379c018060727785a9b"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5c5cfb8bbd3339cd25cca30e7516ff8fe5cb1feeddde6980cc4d5ef34df97bb"
+checksum = "f843932baf8d1025c5f114b929eda172d74b7163d058e0de2597c308b567c7e9"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -145,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c9b0d4269b36fd858e6d8f20cd4938941186fb831488c361888cb2d6b33a9a6"
+checksum = "449819ef1c4af139cf1b9717916fcaea0e23248853d3e95135139773a842d3eb"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -156,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ea0ebdef7aff4a79bcbc8b6495f31315f16b3bf311152f472eaa8d679352581"
+checksum = "3ae2d48f38081a9e679ad795bd36bb29bedeb5552fc1c195185bf9885fa1b16e"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -167,9 +177,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e33439ec20db058bc7cc3410f9748ab1ad90a35cef713d625c736f43e3820d"
+checksum = "3a39ee2cfd0ec485eca76f6b4dc17701a280fa406bc05137bb43f1635ed12c9f"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -279,9 +289,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "object"
-version = "0.36.1"
+version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
+checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
 dependencies = [
  "crc32fast",
  "hashbrown 0.14.5",
@@ -411,9 +421,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "22.0.0"
+version = "23.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91"
+checksum = "7fddf3e2980fb1d123d1fcac55189e417fdd3dba4f62139b5a0a1f9efe5669d5"
 dependencies = [
  "anyhow",
  "cfg-if",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 2969a6cf6ec..a0df502dadc 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.109.0", default-features = false, features = ["std", "unwind", "all-arch"] }
-cranelift-frontend = { version = "0.109.0" }
-cranelift-module = { version = "0.109.0" }
-cranelift-native = { version = "0.109.0" }
-cranelift-jit = { version = "0.109.0", optional = true }
-cranelift-object = { version = "0.109.0" }
+cranelift-codegen = { version = "0.110.1", default-features = false, features = ["std", "unwind", "all-arch"] }
+cranelift-frontend = { version = "0.110.1" }
+cranelift-module = { version = "0.110.1" }
+cranelift-native = { version = "0.110.1" }
+cranelift-jit = { version = "0.110.1", optional = true }
+cranelift-object = { version = "0.110.1" }
 target-lexicon = "0.12.0"
 gimli = { version = "0.28", default-features = false, features = ["write"]}
 object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index 3b3c86a1bd1..6766e2f844d 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -16,7 +16,6 @@ $ rustup component add rustc-codegen-cranelift-preview --toolchain nightly
 
 Once it is installed, you can enable it with one of the following approaches:
 - `CARGO_PROFILE_DEV_CODEGEN_BACKEND=cranelift cargo +nightly build -Zcodegen-backend`
-- `RUSTFLAGS="-Zcodegen-backend=cranelift" cargo +nightly build`
 - Add the following to `.cargo/config.toml`:
     ```toml
     [unstable]
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
index ecf303c30b6..e3f1162445b 100644
--- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
@@ -1,14 +1,13 @@
-use crate::build_sysroot;
-use crate::path::Dirs;
+use crate::path::{Dirs, RelPath};
 use crate::prepare::GitRepo;
 use crate::utils::{spawn_and_wait, CargoProject, Compiler};
-use crate::{CodegenBackend, SysrootKind};
+use crate::{build_sysroot, CodegenBackend, SysrootKind};
 
 static ABI_CAFE_REPO: GitRepo = GitRepo::github(
     "Gankra",
     "abi-cafe",
-    "4c6dc8c9c687e2b3a760ff2176ce236872b37212",
-    "588df6d66abbe105",
+    "f1220cfd13b57f5c0082c26529163865ee25e115",
+    "fe93a9acd461425d",
     "abi-cafe",
 );
 
@@ -22,6 +21,7 @@ pub(crate) fn run(
     rustup_toolchain_name: Option<&str>,
     bootstrap_host_compiler: &Compiler,
 ) {
+    RelPath::DOWNLOAD.ensure_exists(dirs);
     ABI_CAFE_REPO.fetch(dirs);
     ABI_CAFE_REPO.patch(dirs);
 
@@ -39,17 +39,23 @@ pub(crate) fn run(
     eprintln!("Running abi-cafe");
 
     let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
-
-    let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
-    cmd.arg("--");
-    cmd.arg("--pairs");
-    cmd.args(
+    let pairs =
         if cfg!(not(any(target_os = "macos", all(target_os = "windows", target_env = "msvc")))) {
             &pairs[..]
         } else {
             &pairs[..2]
-        },
-    );
+        };
+
+    let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
+    cmd.arg("--");
+
+    // stdcall, vectorcall and such don't work yet
+    cmd.arg("--conventions").arg("c").arg("--conventions").arg("rust");
+
+    for pair in pairs {
+        cmd.arg("--pairs").arg(pair);
+    }
+
     cmd.arg("--add-rustc-codegen-backend");
     match cg_clif_dylib {
         CodegenBackend::Local(path) => {
@@ -59,6 +65,7 @@ pub(crate) fn run(
             cmd.arg(format!("cgclif:{name}"));
         }
     }
+
     cmd.current_dir(ABI_CAFE.source_dir(dirs));
 
     spawn_and_wait(cmd);
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index dfbe0f51e7b..e41f6c5e709 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -1,7 +1,6 @@
-use std::env;
-use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::{env, fs};
 
 use crate::path::{Dirs, RelPath};
 use crate::rustc_info::get_file_name;
@@ -272,7 +271,7 @@ fn build_clif_sysroot_for_triple(
     if channel == "release" {
         build_cmd.arg("--release");
     }
-    build_cmd.arg("--features").arg("backtrace panic-unwind");
+    build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128");
     build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     if compiler.triple.contains("apple") {
@@ -313,7 +312,6 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
         let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
         let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
         build_rtstartup_cmd
-            .arg("-Ainternal_features") // Missing #[allow(internal_features)]
             .arg("--target")
             .arg(&compiler.triple)
             .arg("--emit=obj")
diff --git a/compiler/rustc_codegen_cranelift/build_system/config.rs b/compiler/rustc_codegen_cranelift/build_system/config.rs
index c31784e1097..ef540cf1f82 100644
--- a/compiler/rustc_codegen_cranelift/build_system/config.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/config.rs
@@ -1,5 +1,4 @@
-use std::fs;
-use std::process;
+use std::{fs, process};
 
 fn load_config_file() -> Vec<(String, Option<String>)> {
     fs::read_to_string("config.txt")
diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs
index 7dbf608f991..9ddeda583af 100644
--- a/compiler/rustc_codegen_cranelift/build_system/main.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/main.rs
@@ -2,9 +2,8 @@
 #![warn(unused_lifetimes)]
 #![warn(unreachable_pub)]
 
-use std::env;
 use std::path::PathBuf;
-use std::process;
+use std::{env, process};
 
 use self::utils::Compiler;
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 5525a5f63e9..be0bed0f4e6 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -22,36 +22,6 @@ pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) {
     assert!(sysroot_src_orig.exists());
 
     apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs));
-
-    std::fs::write(
-        STDLIB_SRC.to_path(dirs).join("Cargo.toml"),
-        r#"
-[workspace]
-resolver = "1"
-members = ["./library/sysroot"]
-
-[patch.crates-io]
-rustc-std-workspace-core = { path = "./library/rustc-std-workspace-core" }
-rustc-std-workspace-alloc = { path = "./library/rustc-std-workspace-alloc" }
-rustc-std-workspace-std = { path = "./library/rustc-std-workspace-std" }
-
-# Mandatory for correctly compiling compiler-builtins
-[profile.dev.package.compiler_builtins]
-debug-assertions = false
-overflow-checks = false
-codegen-units = 10000
-
-[profile.release.package.compiler_builtins]
-debug-assertions = false
-overflow-checks = false
-codegen-units = 10000
-"#,
-    )
-    .unwrap();
-
-    let source_lockfile = RelPath::PATCHES.to_path(dirs).join("stdlib-lock.toml");
-    let target_lockfile = STDLIB_SRC.to_path(dirs).join("Cargo.lock");
-    fs::copy(source_lockfile, target_lockfile).unwrap();
 }
 
 pub(crate) struct GitRepo {
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 790d9cbd9fc..38c3786a94a 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -3,14 +3,12 @@ use std::fs;
 use std::path::PathBuf;
 use std::process::Command;
 
-use crate::build_sysroot;
-use crate::config;
 use crate::path::{Dirs, RelPath};
 use crate::prepare::{apply_patches, GitRepo};
 use crate::rustc_info::get_default_sysroot;
 use crate::shared_utils::rustflags_from_env;
 use crate::utils::{spawn_and_wait, CargoProject, Compiler, LogGroup};
-use crate::{CodegenBackend, SysrootKind};
+use crate::{build_sysroot, config, CodegenBackend, SysrootKind};
 
 static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
 
@@ -108,6 +106,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
         ]);
         runner.run_out_command("gen_block_iterate", &[]);
     }),
+    TestCase::build_bin_and_run("aot.raw-dylib", "example/raw-dylib.rs", &[]),
 ];
 
 pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
@@ -439,7 +438,7 @@ impl<'a> TestRunner<'a> {
         cmd.arg("-L");
         cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
         cmd.arg("--out-dir");
-        cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
+        cmd.arg(BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs));
         cmd.arg("-Cdebuginfo=2");
         cmd.arg("--target");
         cmd.arg(&self.target_compiler.triple);
diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs
index 9f95122b341..3c4b45e02cc 100644
--- a/compiler/rustc_codegen_cranelift/build_system/utils.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs
@@ -1,9 +1,7 @@
-use std::env;
-use std::fs;
-use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{self, Command};
 use std::sync::atomic::{AtomicBool, Ordering};
+use std::{env, fs, io};
 
 use crate::path::{Dirs, RelPath};
 use crate::shared_utils::rustflags_to_cmd_env;
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index 0b7cac18837..527ec5303b6 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -45,6 +45,7 @@ aot.issue-59326
 aot.polymorphize_coroutine
 aot.neon
 aot.gen_block_iterate
+aot.raw-dylib
 
 testsuite.extended_sysroot
 test.rust-random/rand
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_system.rs b/compiler/rustc_codegen_cranelift/example/alloc_system.rs
index 441f3cd2987..2884c9c32ae 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_system.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_system.rs
@@ -8,8 +8,7 @@ pub struct System;
 #[cfg(any(windows, unix, target_os = "redox"))]
 mod realloc_fallback {
     use core::alloc::{GlobalAlloc, Layout};
-    use core::cmp;
-    use core::ptr;
+    use core::{cmp, ptr};
     impl super::System {
         pub(crate) unsafe fn realloc_fallback(
             &self,
@@ -34,6 +33,7 @@ mod platform {
     use core::alloc::{GlobalAlloc, Layout};
     use core::ffi::c_void;
     use core::ptr;
+
     use System;
     extern "C" {
         fn posix_memalign(memptr: *mut *mut c_void, align: usize, size: usize) -> i32;
@@ -71,6 +71,7 @@ mod platform {
 #[allow(nonstandard_style)]
 mod platform {
     use core::alloc::{GlobalAlloc, Layout};
+
     use System;
     type LPVOID = *mut u8;
     type HANDLE = LPVOID;
diff --git a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
index f7edfa960a2..5479b0c617b 100644
--- a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -2,10 +2,8 @@
 
 #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
 
-use std::{
-    marker::Unsize,
-    ops::{CoerceUnsized, Deref, DispatchFromDyn},
-};
+use std::marker::Unsize;
+use std::ops::{CoerceUnsized, Deref, DispatchFromDyn};
 
 struct Ptr<T: ?Sized>(Box<T>);
 
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 7d361a9ab2b..e603ac566f4 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -585,6 +585,7 @@ pub enum E2<X> {
     V4,
 }
 
+#[allow(unreachable_patterns)]
 fn check_niche_behavior() {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
diff --git a/compiler/rustc_codegen_cranelift/example/raw-dylib.rs b/compiler/rustc_codegen_cranelift/example/raw-dylib.rs
new file mode 100644
index 00000000000..4711884f76a
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/example/raw-dylib.rs
@@ -0,0 +1,31 @@
+// Tests the raw-dylib feature for Windows.
+// https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute
+
+fn main() {
+    #[cfg(windows)]
+    {
+        #[link(name = "kernel32", kind = "raw-dylib")]
+        extern "C" {
+            fn GetModuleFileNameA(
+                module: *mut std::ffi::c_void,
+                filename: *mut u8,
+                size: u32,
+            ) -> u32;
+        }
+
+        // Get the filename of the current executable....
+        let mut buffer = [0u8; 1024];
+        let size = unsafe {
+            GetModuleFileNameA(core::ptr::null_mut(), buffer.as_mut_ptr(), buffer.len() as u32)
+        };
+        if size == 0 {
+            eprintln!("failed to get module file name: {}", std::io::Error::last_os_error());
+            return;
+        } else {
+            // ...and make sure that it matches the test name.
+            let filename =
+                std::ffi::CStr::from_bytes_with_nul(&buffer[..size as usize + 1]).unwrap();
+            assert!(filename.to_str().unwrap().ends_with("raw-dylib.exe"));
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
deleted file mode 100644
index 77716c51399..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 2b15fee2bb5fd14e34c7e17e44d99cb34f4c555d Mon Sep 17 00:00:00 2001
-From: Afonso Bordado <afonsobordado@az8.co>
-Date: Tue, 27 Sep 2022 07:55:17 +0100
-Subject: [PATCH] Disable some test on x86_64-pc-windows-gnu
-
----
- src/report.rs | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/src/report.rs b/src/report.rs
-index eeec614..f582867 100644
---- a/src/report.rs
-+++ b/src/report.rs
-@@ -48,6 +48,15 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
-     //
-     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
- 
-+    // x86_64-pc-windows-gnu has some broken i128 tests that aren't disabled by default
-+    if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" {
-+        result.run = Link;
-+        result.check = Pass(Link);
-+    } else if test.test_name == "ui128" {
-+        result.run == Check;
-+        result.check = Pass(Check);
-+    }
-+
-     // END OF VENDOR RESERVED AREA
-     //
-     //
--- 
-2.30.1.windows.1
-
diff --git a/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch b/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch
new file mode 100644
index 00000000000..8a2565f1668
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch
@@ -0,0 +1,75 @@
+From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001
+From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
+Date: Tue, 9 Jul 2024 11:25:14 +0000
+Subject: [PATCH] Disable broken tests
+
+---
+ src/report.rs | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/src/report.rs b/src/report.rs
+index 958ab43..dcf1044 100644
+--- a/src/report.rs
++++ b/src/report.rs
+@@ -48,6 +48,58 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc
+     //
+     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
+ 
++    if cfg!(all(target_arch = "aarch64", target_os = "linux")) {
++        if test.test == "F32Array" && test.options.convention == CallingConvention::C {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
++            result.check = Busted(Check);
++        }
++    }
++
++    if cfg!(all(target_arch = "aarch64", target_os = "macos")) {
++        if test.test == "SingleVariantUnion" && test.options.convention == CallingConvention::C && test.options.repr == LangRepr::C {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "OptionU128" && test.caller == "rustc" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
++            result.check = Busted(Run);
++        }
++
++        if test.test == "OptionU128" && test.caller == "cgclif" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
++            result.check = Busted(Check);
++        }
++    }
++
++    if cfg!(all(target_arch = "x86_64", unix)) {
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::Rust {
++            result.check = Busted(Run);
++        }
++    }
++
++    if cfg!(all(target_arch = "x86_64", windows)) {
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && (test.caller == "rustc" || test.options.repr == LangRepr::Rust) {
++            result.check = Busted(Run);
++        }
++
++        if test.test == "simple" && test.options.convention == CallingConvention::Rust {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "simple" && test.options.convention == CallingConvention::Rust && test.caller == "rustc" {
++            result.check = Busted(Run);
++        }
++    }
++
++    if test.test == "f16" || test.test == "f128" {
++        result.run = Skip;
++    }
++
+     // END OF VENDOR RESERVED AREA
+     //
+     //
+-- 
+2.34.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
index 7cf7f86700e..8c404956bcc 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
@@ -37,8 +37,8 @@ index 42a26ae..5ac1042 100644
 +++ b/lib.rs
 @@ -1,3 +1,4 @@
 +#![cfg(test)]
- #![feature(alloc_layout_extra)]
- #![feature(array_chunks)]
- #![feature(array_ptr_get)]
+ // tidy-alphabetical-start
+ #![cfg_attr(bootstrap, feature(offset_of_nested))]
+ #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
 --
 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
index 271ca12eabb..d579c9588f0 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
@@ -11,17 +11,17 @@ Cranelift doesn't support them yet
  4 files changed, 4 insertions(+), 50 deletions(-)
 
 diff --git a/lib.rs b/lib.rs
-index 897a5e9..331f66f 100644
+index 1e336bf..35e6f54 100644
 --- a/lib.rs
 +++ b/lib.rs
-@@ -93,7 +93,6 @@
- #![feature(const_option)]
- #![feature(const_option_ext)]
- #![feature(const_result)]
+@@ -1,7 +1,6 @@
+ #![cfg(test)]
+ // tidy-alphabetical-start
+ #![cfg_attr(bootstrap, feature(offset_of_nested))]
 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
  #![cfg_attr(test, feature(cfg_match))]
- #![feature(int_roundings)]
- #![feature(split_array)]
+ #![feature(alloc_layout_extra)]
+ #![feature(array_chunks)]
 diff --git a/atomic.rs b/atomic.rs
 index b735957..ea728b6 100644
 --- a/atomic.rs
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
new file mode 100644
index 00000000000..ada35145e29
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
@@ -0,0 +1,25 @@
+From 175d52c5e1779764b66777db1e6f172c2dc365ff Mon Sep 17 00:00:00 2001
+From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
+Date: Fri, 9 Aug 2024 15:44:51 +0000
+Subject: [PATCH] Disable f16 and f128 in compiler-builtins
+
+---
+ library/sysroot/Cargo.toml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
+index 7165c3e48af..968552ad435 100644
+--- a/library/sysroot/Cargo.toml
++++ b/library/sysroot/Cargo.toml
+@@ -11,7 +11,7 @@ test = { path = "../test" }
+ 
+ # Forward features to the `std` crate as necessary
+ [features]
+-default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
++default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind", "compiler-builtins-no-f16-f128"]
+ backtrace = ["std/backtrace"]
+ compiler-builtins-c = ["std/compiler-builtins-c"]
+ compiler-builtins-mem = ["std/compiler-builtins-mem"]
+-- 
+2.34.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
deleted file mode 100644
index 584dbdb647f..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 9f65e742ba3e41474e6126c6c4469c48eaa6ca7e Mon Sep 17 00:00:00 2001
-From: Chris Denton <chris@chrisdenton.dev>
-Date: Tue, 20 Feb 2024 16:01:40 -0300
-Subject: [PATCH] Don't use raw-dylib in std
-
----
- library/std/src/sys/pal/windows/c.rs    | 2 +-
- library/std/src/sys/pal/windows/rand.rs | 3 +--
- 2 files changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
-index ad8e01bfa9b..9ca8e4c16ce 100644
---- a/library/std/src/sys/pal/windows/c.rs
-+++ b/library/std/src/sys/pal/windows/c.rs
-@@ -312,7 +312,7 @@ pub unsafe fn NtWriteFile(
- 
- // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
- cfg_if::cfg_if! {
--if #[cfg(not(target_vendor = "win7"))] {
-+if #[cfg(any())] {
-     #[cfg(target_arch = "x86")]
-     #[link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")]
-     extern "system" {
-diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs
-index e427546222a..f2fe42a4d51 100644
---- a/library/std/src/sys/pal/windows/rand.rs
-+++ b/library/std/src/sys/pal/windows/rand.rs
-@@ -2,7 +2,7 @@
- 
- use crate::sys::c;
- 
--#[cfg(not(target_vendor = "win7"))]
-+#[cfg(any())]
- #[inline]
- pub fn hashmap_random_keys() -> (u64, u64) {
-     let mut v = (0, 0);
-@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
-     v
- }
- 
--#[cfg(target_vendor = "win7")]
- pub fn hashmap_random_keys() -> (u64, u64) {
-     use crate::ffi::c_void;
-     use crate::io;
--- 
-2.42.0.windows.2
-
diff --git a/compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch b/compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch
deleted file mode 100644
index 21f5ee9cc6e..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0d741cf82c3c908616abd39dc84ebf7d8702e0c3 Mon Sep 17 00:00:00 2001
-From: Chris Denton <chris@chrisdenton.dev>
-Date: Tue, 16 Apr 2024 15:51:34 +0000
-Subject: [PATCH] Revert use raw-dylib for Windows futex APIs
-
----
- library/std/src/sys/pal/windows/c.rs | 14 +-------------
- 1 file changed, 1 insertion(+), 13 deletions(-)
-
-diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
-index 9d58ce05f01..1c828bac4b6 100644
---- a/library/std/src/sys/pal/windows/c.rs
-+++ b/library/std/src/sys/pal/windows/c.rs
-@@ -357,19 +357,7 @@ pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
- }
- 
- #[cfg(not(target_vendor = "win7"))]
--// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library.
--#[cfg_attr(
--    target_arch = "x86",
--    link(
--        name = "api-ms-win-core-synch-l1-2-0",
--        kind = "raw-dylib",
--        import_name_type = "undecorated"
--    )
--)]
--#[cfg_attr(
--    not(target_arch = "x86"),
--    link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
--)]
-+#[link(name = "synchronization")]
- extern "system" {
-     pub fn WaitOnAddress(
-         address: *const c_void,
--- 
-2.42.0.windows.2
-
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
deleted file mode 100644
index 9ea53e8f848..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ /dev/null
@@ -1,455 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "addr2line"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
-dependencies = [
- "compiler_builtins",
- "gimli 0.29.0",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "alloc"
-version = "0.0.0"
-dependencies = [
- "compiler_builtins",
- "core",
- "rand",
- "rand_xorshift",
-]
-
-[[package]]
-name = "allocator-api2"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
-
-[[package]]
-name = "cc"
-version = "1.0.97"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "compiler_builtins"
-version = "0.1.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4ab134a739bafec76aa91ccb15d519a54e569350644a1fea6528d5a0d407e22"
-dependencies = [
- "cc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "core"
-version = "0.0.0"
-dependencies = [
- "rand",
- "rand_xorshift",
-]
-
-[[package]]
-name = "cupid"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bad352a84b567cc38a5854e3aa8ee903cb8519a25d0b799b739bafffd1f91a1"
-dependencies = [
- "gcc",
- "rustc_version",
-]
-
-[[package]]
-name = "dlmalloc"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a"
-dependencies = [
- "compiler_builtins",
- "libc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "fortanix-sgx-abi"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "gcc"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-
-[[package]]
-name = "getopts"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
-dependencies = [
- "rustc-std-workspace-core",
- "rustc-std-workspace-std",
- "unicode-width",
-]
-
-[[package]]
-name = "gimli"
-version = "0.28.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "gimli"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.14.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
-dependencies = [
- "allocator-api2",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "hermit-abi"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.153"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
-dependencies = [
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "memchr"
-version = "2.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
-dependencies = [
- "adler",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "object"
-version = "0.36.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
-dependencies = [
- "compiler_builtins",
- "memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "panic_abort"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
-]
-
-[[package]]
-name = "panic_unwind"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
- "unwind",
-]
-
-[[package]]
-name = "proc_macro"
-version = "0.0.0"
-dependencies = [
- "core",
- "std",
-]
-
-[[package]]
-name = "profiler_builtins"
-version = "0.0.0"
-dependencies = [
- "cc",
- "compiler_builtins",
- "core",
-]
-
-[[package]]
-name = "r-efi"
-version = "4.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "r-efi-alloc"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
-dependencies = [
- "compiler_builtins",
- "r-efi",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-
-[[package]]
-name = "rand_xorshift"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "rustc-std-workspace-alloc"
-version = "1.99.0"
-dependencies = [
- "alloc",
-]
-
-[[package]]
-name = "rustc-std-workspace-core"
-version = "1.99.0"
-dependencies = [
- "core",
-]
-
-[[package]]
-name = "rustc-std-workspace-std"
-version = "1.99.0"
-dependencies = [
- "std",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
-[[package]]
-name = "std"
-version = "0.0.0"
-dependencies = [
- "addr2line",
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "dlmalloc",
- "fortanix-sgx-abi",
- "hashbrown",
- "hermit-abi",
- "libc",
- "miniz_oxide",
- "object",
- "panic_abort",
- "panic_unwind",
- "profiler_builtins",
- "r-efi",
- "r-efi-alloc",
- "rand",
- "rand_xorshift",
- "rustc-demangle",
- "std_detect",
- "unwind",
- "wasi",
-]
-
-[[package]]
-name = "std_detect"
-version = "0.1.5"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "cupid",
- "libc",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "sysroot"
-version = "0.0.0"
-dependencies = [
- "proc_macro",
- "std",
- "test",
-]
-
-[[package]]
-name = "test"
-version = "0.0.0"
-dependencies = [
- "core",
- "getopts",
- "libc",
- "std",
-]
-
-[[package]]
-name = "unicode-width"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
- "rustc-std-workspace-std",
-]
-
-[[package]]
-name = "unwind"
-version = "0.0.0"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
- "unwinding",
-]
-
-[[package]]
-name = "unwinding"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
-dependencies = [
- "compiler_builtins",
- "gimli 0.28.1",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index db9b551bd2a..96c467e091c 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,4 @@
 [toolchain]
-channel = "nightly-2024-07-13"
+channel = "nightly-2024-08-09"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
+profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/rustfmt.toml b/compiler/rustc_codegen_cranelift/rustfmt.toml
index 6f4d4413c25..d9e6ac3d543 100644
--- a/compiler/rustc_codegen_cranelift/rustfmt.toml
+++ b/compiler/rustc_codegen_cranelift/rustfmt.toml
@@ -6,3 +6,5 @@ ignore = [
 version = "Two"
 use_small_heuristics = "Max"
 merge_derives = false
+group_imports = "StdExternalCrate"
+imports_granularity = "Module"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index f0550c23b17..bb5af9127b9 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -39,6 +39,7 @@ rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.r
 # exotic linkages
 rm tests/incremental/hashes/function_interfaces.rs
 rm tests/incremental/hashes/statics.rs
+rm -r tests/run-make/naked-symbol-visibility
 
 # variadic arguments
 rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
@@ -118,6 +119,7 @@ rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm tests/ui/mir/mir_raw_fat_ptr.rs # same
 rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/consts/const-mut-refs-crate.rs # same
+rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift
 
 # doesn't work due to the way the rustc test suite is invoked.
 # should work when using ./x.py test the way it is intended
@@ -134,6 +136,8 @@ rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation war
 # bugs in the test suite
 # ======================
 rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
+rm tests/ui/backtrace/synchronized-panic-handler.rs # missing needs-unwind annotation
+rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables
 
 rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
@@ -157,8 +161,8 @@ index ea06b620c4c..b969d0009c6 100644
  RUSTDOC := \$(RUSTDOC) -Clinker='\$(RUSTC_LINKER)'
 diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
 index 9607ff02f96..b7d97caf9a2 100644
---- a/src/tools/run-make-support/src/rustdoc.rs
-+++ b/src/tools/run-make-support/src/rustdoc.rs
+--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
++++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
 @@ -34,8 +34,6 @@ pub fn bare() -> Self {
      #[track_caller]
      pub fn new() -> Self {
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 1935005a08c..5eedab4f2cb 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -1,8 +1,13 @@
-use std::path::{Path, PathBuf};
+use std::borrow::Borrow;
+use std::fs;
+use std::path::Path;
 
+use ar_archive_writer::{COFFShortExport, MachineTypes};
 use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
+    create_mingw_dll_import_lib, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
+    DEFAULT_OBJECT_READER,
 };
+use rustc_codegen_ssa::common::is_mingw_gnu_toolchain;
 use rustc_session::Session;
 
 pub(crate) struct ArArchiveBuilderBuilder;
@@ -15,11 +20,74 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
     fn create_dll_import_lib(
         &self,
         sess: &Session,
-        _lib_name: &str,
-        _dll_imports: &[rustc_session::cstore::DllImport],
-        _tmpdir: &Path,
-        _is_direct_dependency: bool,
-    ) -> PathBuf {
-        sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift");
+        lib_name: &str,
+        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        output_path: &Path,
+    ) {
+        if is_mingw_gnu_toolchain(&sess.target) {
+            // The binutils linker used on -windows-gnu targets cannot read the import
+            // libraries generated by LLVM: in our attempts, the linker produced an .EXE
+            // that loaded but crashed with an AV upon calling one of the imported
+            // functions. Therefore, use binutils to create the import library instead,
+            // by writing a .DEF file to the temp dir and calling binutils's dlltool.
+            create_mingw_dll_import_lib(
+                sess,
+                lib_name,
+                import_name_and_ordinal_vector,
+                output_path,
+            );
+        } else {
+            let mut file =
+                match fs::OpenOptions::new().write(true).create_new(true).open(&output_path) {
+                    Ok(file) => file,
+                    Err(error) => {
+                        sess.dcx().fatal(format!(
+                            "failed to create import library file `{path}`: {error}",
+                            path = output_path.display(),
+                        ));
+                    }
+                };
+
+            let machine = match sess.target.arch.borrow() {
+                "x86" => MachineTypes::I386,
+                "x86_64" => MachineTypes::AMD64,
+                "arm" => MachineTypes::ARMNT,
+                "aarch64" => MachineTypes::ARM64,
+                _ => {
+                    sess.dcx().fatal(format!(
+                        "unsupported target architecture `{arch}`",
+                        arch = sess.target.arch,
+                    ));
+                }
+            };
+
+            let exports = import_name_and_ordinal_vector
+                .iter()
+                .map(|(name, ordinal)| COFFShortExport {
+                    name: name.to_string(),
+                    ext_name: None,
+                    symbol_name: None,
+                    alias_target: None,
+                    ordinal: ordinal.unwrap_or(0),
+                    noname: ordinal.is_some(),
+                    data: false,
+                    private: false,
+                    constant: false,
+                })
+                .collect::<Vec<_>>();
+
+            if let Err(error) = ar_archive_writer::write_import_library(
+                &mut file,
+                lib_name,
+                &exports,
+                machine,
+                !sess.target.is_like_msvc,
+            ) {
+                sess.dcx().fatal(format!(
+                    "failed to create import library `{path}`: `{error}`",
+                    path = output_path.display(),
+                ));
+            }
+        }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index e16b77648d1..b6a4769e031 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -23,19 +23,7 @@ pub(crate) fn maybe_codegen<'tcx>(
     match bin_op {
         BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None,
         BinOp::Add | BinOp::AddUnchecked | BinOp::Sub | BinOp::SubUnchecked => None,
-        BinOp::Mul | BinOp::MulUnchecked => {
-            let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
-            let ret_val = fx.lib_call(
-                "__multi3",
-                vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
-                vec![AbiParam::new(types::I128)],
-                &args,
-            )[0];
-            Some(CValue::by_val(
-                ret_val,
-                fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
-            ))
-        }
+        BinOp::Mul | BinOp::MulUnchecked => None,
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => {
             let name = match (bin_op, is_signed) {
@@ -92,6 +80,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
 
     match bin_op {
         BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
+        BinOp::Add | BinOp::Sub => None,
         BinOp::Mul if is_signed => {
             let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
             let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
@@ -112,7 +101,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
             let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
             Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
         }
-        BinOp::Add | BinOp::Sub | BinOp::Mul => {
+        BinOp::Mul => {
             let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
             let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
             let param_types = vec![
@@ -121,15 +110,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
                 AbiParam::new(types::I128),
             ];
             let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
-            let name = match (bin_op, is_signed) {
-                (BinOp::Add, false) => "__rust_u128_addo",
-                (BinOp::Add, true) => "__rust_i128_addo",
-                (BinOp::Sub, false) => "__rust_u128_subo",
-                (BinOp::Sub, true) => "__rust_i128_subo",
-                (BinOp::Mul, false) => "__rust_u128_mulo",
-                _ => unreachable!(),
-            };
-            fx.lib_call(name, param_types, vec![], &args);
+            fx.lib_call("__rust_u128_mulo", param_types, vec![], &args);
             Some(out_place.to_cvalue(fx))
         }
         BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 09317139936..a1b29a42225 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -107,7 +107,7 @@ pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         return false;
     }
 
-    let tail = tcx.struct_tail_erasing_lifetimes(ty, ParamEnv::reveal_all());
+    let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all());
     match tail.kind() {
         ty::Foreign(..) => false,
         ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
index f3b963200a0..4154a62234c 100644
--- a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
+++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
@@ -38,18 +38,12 @@ builtin_functions! {
     register_functions_for_jit;
 
     // integers
-    fn __multi3(a: i128, b: i128) -> i128;
     fn __muloti4(n: i128, d: i128, oflow: &mut i32) -> i128;
     fn __udivti3(n: u128, d: u128) -> u128;
     fn __divti3(n: i128, d: i128) -> i128;
     fn __umodti3(n: u128, d: u128) -> u128;
     fn __modti3(n: i128, d: i128) -> i128;
-    fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool);
-    fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool);
-    fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool);
-    fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool);
     fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool);
-    fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool);
 
     // floats
     fn __floattisf(i: i128) -> f32;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index eebd181341d..ac7dd0bd463 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -1,7 +1,8 @@
 //! Unwind info generation (`.eh_frame`)
 
 use cranelift_codegen::ir::Endianness;
-use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
+use cranelift_codegen::isa::unwind::UnwindInfo;
+use cranelift_codegen::isa::TargetIsa;
 use cranelift_object::ObjectProduct;
 use gimli::write::{CieId, EhFrame, FrameTable, Section};
 use gimli::RunTimeEndian;
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 763d9a48407..b6fee1bf24a 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -11,8 +11,9 @@ use rustc_codegen_ssa::assert_module_sources::CguReuse;
 use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
 use rustc_codegen_ssa::base::determine_cgu_reuse;
-use rustc_codegen_ssa::errors as ssa_errors;
-use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
+use rustc_codegen_ssa::{
+    errors as ssa_errors, CodegenResults, CompiledModule, CrateInfo, ModuleKind,
+};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{par_map, IntoDynSyncSend};
@@ -26,8 +27,9 @@ use rustc_session::Session;
 use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
 use crate::debuginfo::TypeDebugContext;
 use crate::global_asm::GlobalAsmConfig;
+use crate::prelude::*;
 use crate::unwind_module::UnwindModule;
-use crate::{prelude::*, BackendConfig};
+use crate::BackendConfig;
 
 struct ModuleCodegenResult {
     module_regular: CompiledModule,
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index dfee8e714e6..12e860f676d 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -14,9 +14,9 @@ use rustc_session::Session;
 use rustc_span::Symbol;
 
 use crate::debuginfo::TypeDebugContext;
+use crate::prelude::*;
 use crate::unwind_module::UnwindModule;
-use crate::{prelude::*, BackendConfig};
-use crate::{CodegenCx, CodegenMode};
+use crate::{BackendConfig, CodegenCx, CodegenMode};
 
 struct JitState {
     jit_module: UnwindModule<JITModule>,
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index a20faa2cad3..cb003037c26 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -169,39 +169,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             }
         }
 
-        "llvm.x86.sse.add.ss" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_ss&ig_expand=171
-            intrinsic_args!(fx, args => (a, b); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), ret.layout());
-            let layout = a.layout();
-
-            let (_, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            let ret_lane_layout = fx.layout_of(lane_ty);
-
-            ret.write_cvalue(fx, a);
-
-            let a_lane = a.value_lane(fx, 0).load_scalar(fx);
-            let b_lane = b.value_lane(fx, 0).load_scalar(fx);
-
-            let res = fx.bcx.ins().fadd(a_lane, b_lane);
-
-            let res_lane = CValue::by_val(res, ret_lane_layout);
-            ret.place_lane(fx, 0).write_cvalue(fx, res_lane);
-        }
-
-        "llvm.x86.sse.sqrt.ps" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sqrt_ps&ig_expand=6245
-            intrinsic_args!(fx, args => (a); intrinsic);
-
-            // FIXME use vector instructions when possible
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
-                fx.bcx.ins().sqrt(lane)
-            });
-        }
-
         "llvm.x86.sse.max.ps" => {
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_ps&ig_expand=4357
             intrinsic_args!(fx, args => (a, b); intrinsic);
@@ -744,117 +711,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Avx);
         }
 
-        "llvm.x86.fma.vfmaddsub.ps"
-        | "llvm.x86.fma.vfmaddsub.pd"
-        | "llvm.x86.fma.vfmaddsub.ps.256"
-        | "llvm.x86.fma.vfmaddsub.pd.256" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmaddsub_ps&ig_expand=3205
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmaddsub_pd&ig_expand=3181
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmaddsub_ps&ig_expand=3209
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmaddsub_pd&ig_expand=3185
-            intrinsic_args!(fx, args => (a, b, c); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
-
-            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            assert!(ret_lane_ty.is_floating_point());
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
-
-            for idx in 0..lane_count {
-                let a_lane = a.value_lane(fx, idx).load_scalar(fx);
-                let b_lane = b.value_lane(fx, idx).load_scalar(fx);
-                let c_lane = c.value_lane(fx, idx).load_scalar(fx);
-
-                let mul = fx.bcx.ins().fmul(a_lane, b_lane);
-                let res = if idx & 1 == 0 {
-                    fx.bcx.ins().fsub(mul, c_lane)
-                } else {
-                    fx.bcx.ins().fadd(mul, c_lane)
-                };
-
-                let res_lane = CValue::by_val(res, ret_lane_layout);
-                ret.place_lane(fx, idx).write_cvalue(fx, res_lane);
-            }
-        }
-
-        "llvm.x86.fma.vfmsubadd.ps"
-        | "llvm.x86.fma.vfmsubadd.pd"
-        | "llvm.x86.fma.vfmsubadd.ps.256"
-        | "llvm.x86.fma.vfmsubadd.pd.256" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmsubadd_ps&ig_expand=3325
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmsubadd_pd&ig_expand=3301
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmsubadd_ps&ig_expand=3329
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmsubadd_pd&ig_expand=3305
-            intrinsic_args!(fx, args => (a, b, c); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
-
-            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            assert!(ret_lane_ty.is_floating_point());
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
-
-            for idx in 0..lane_count {
-                let a_lane = a.value_lane(fx, idx).load_scalar(fx);
-                let b_lane = b.value_lane(fx, idx).load_scalar(fx);
-                let c_lane = c.value_lane(fx, idx).load_scalar(fx);
-
-                let mul = fx.bcx.ins().fmul(a_lane, b_lane);
-                let res = if idx & 1 == 0 {
-                    fx.bcx.ins().fadd(mul, c_lane)
-                } else {
-                    fx.bcx.ins().fsub(mul, c_lane)
-                };
-
-                let res_lane = CValue::by_val(res, ret_lane_layout);
-                ret.place_lane(fx, idx).write_cvalue(fx, res_lane);
-            }
-        }
-
-        "llvm.x86.fma.vfnmadd.ps"
-        | "llvm.x86.fma.vfnmadd.pd"
-        | "llvm.x86.fma.vfnmadd.ps.256"
-        | "llvm.x86.fma.vfnmadd.pd.256" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fnmadd_ps&ig_expand=3391
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fnmadd_pd&ig_expand=3367
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fnmadd_ps&ig_expand=3395
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fnmadd_pd&ig_expand=3371
-            intrinsic_args!(fx, args => (a, b, c); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
-
-            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            assert!(ret_lane_ty.is_floating_point());
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
-
-            for idx in 0..lane_count {
-                let a_lane = a.value_lane(fx, idx).load_scalar(fx);
-                let b_lane = b.value_lane(fx, idx).load_scalar(fx);
-                let c_lane = c.value_lane(fx, idx).load_scalar(fx);
-
-                let mul = fx.bcx.ins().fmul(a_lane, b_lane);
-                let neg_mul = fx.bcx.ins().fneg(mul);
-                let res = fx.bcx.ins().fadd(neg_mul, c_lane);
-
-                let res_lane = CValue::by_val(res, ret_lane_layout);
-                ret.place_lane(fx, idx).write_cvalue(fx, res_lane);
-            }
-        }
-
         "llvm.x86.sse42.crc32.32.8"
         | "llvm.x86.sse42.crc32.32.16"
         | "llvm.x86.sse42.crc32.32.32"
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index b21c559e668..29deac60730 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -725,7 +725,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             // Cranelift treats stores as volatile by default
             // FIXME correctly handle unaligned_volatile_store
-            // FIXME actually do nontemporal stores if requested
+            // FIXME actually do nontemporal stores if requested (but do not just emit MOVNT on x86;
+            // see the LLVM backend for details)
             let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
             dest.write_cvalue(fx, val);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 8d3d5ac98e1..21930fa2ddb 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -12,6 +12,7 @@
 #![warn(unused_lifetimes)]
 // tidy-alphabetical-end
 
+extern crate ar_archive_writer;
 extern crate jobserver;
 #[macro_use]
 extern crate rustc_middle;
@@ -85,10 +86,9 @@ mod vtable;
 mod prelude {
     pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
     pub(crate) use cranelift_codegen::ir::function::Function;
-    pub(crate) use cranelift_codegen::ir::types;
     pub(crate) use cranelift_codegen::ir::{
-        AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot,
-        StackSlotData, StackSlotKind, TrapCode, Type, Value,
+        types, AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
+        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
     };
     pub(crate) use cranelift_codegen::Context;
     pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module};
@@ -191,9 +191,20 @@ impl CodegenBackend for CraneliftCodegenBackend {
         if sess.target.arch == "x86_64" && sess.target.os != "none" {
             // x86_64 mandates SSE2 support
             vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")]
-        } else if sess.target.arch == "aarch64" && sess.target.os != "none" {
-            // AArch64 mandates Neon support
-            vec![sym::neon]
+        } else if sess.target.arch == "aarch64" {
+            match &*sess.target.os {
+                "none" => vec![],
+                // On macOS the aes, sha2 and sha3 features are enabled by default and ring
+                // fails to compile on macOS when they are not present.
+                "macos" => vec![
+                    sym::neon,
+                    Symbol::intern("aes"),
+                    Symbol::intern("sha2"),
+                    Symbol::intern("sha3"),
+                ],
+                // AArch64 mandates Neon support
+                _ => vec![sym::neon],
+            }
         } else {
             vec![]
         }
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index fe0a1551419..ba20a750d2b 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -1,7 +1,6 @@
 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
 use rustc_hir::LangItem;
-use rustc_middle::ty::AssocKind;
-use rustc_middle::ty::GenericArg;
+use rustc_middle::ty::{AssocKind, GenericArg};
 use rustc_session::config::{sigpipe, EntryFnType};
 use rustc_span::symbol::Ident;
 use rustc_span::DUMMY_SP;
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
index 26327dca299..c93fe935210 100644
--- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
+++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
@@ -1,6 +1,7 @@
 //! Peephole optimizations that can be performed while creating clif ir.
 
-use cranelift_codegen::ir::{condcodes::IntCC, InstructionData, Opcode, Value, ValueDef};
+use cranelift_codegen::ir::condcodes::IntCC;
+use cranelift_codegen::ir::{InstructionData, Opcode, Value, ValueDef};
 use cranelift_frontend::FunctionBuilder;
 
 /// If the given value was produced by the lowering of `Rvalue::Not` return the input and true,
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 967aa53abbd..e09cd16e89a 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -22,7 +22,7 @@ pub(crate) fn unsized_info<'tcx>(
     old_info: Option<Value>,
 ) -> Value {
     let (source, target) =
-        fx.tcx.struct_lockstep_tails_erasing_lifetimes(source, target, ParamEnv::reveal_all());
+        fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all());
     match (&source.kind(), &target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => fx
             .bcx
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 1aa28daeafc..8eb2095e523 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -677,8 +677,10 @@ impl<'tcx> CPlace<'tcx> {
                         let to_addr = to_ptr.get_addr(fx);
                         let src_layout = from.1;
                         let size = dst_layout.size.bytes();
-                        let src_align = src_layout.align.abi.bytes() as u8;
-                        let dst_align = dst_layout.align.abi.bytes() as u8;
+                        // `emit_small_memory_copy` uses `u8` for alignments, just use the maximum
+                        // alignment that fits in a `u8` if the actual alignment is larger.
+                        let src_align = src_layout.align.abi.bytes().try_into().unwrap_or(128);
+                        let dst_align = dst_layout.align.abi.bytes().try_into().unwrap_or(128);
                         fx.bcx.emit_small_memory_copy(
                             fx.target_config,
                             to_addr,
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
index d6ec1f87d01..771f2f18dce 100644
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
@@ -50,7 +50,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.109"
+version = "0.1.118"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e"
 dependencies = [
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
index e4669923623..05503128f2a 100644
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
@@ -6,9 +6,7 @@ resolver = "2"
 
 [dependencies]
 core = { path = "./sysroot_src/library/core" }
-# TODO: after the sync, revert to using version 0.1.
-# compiler_builtins = "0.1"
-compiler_builtins = "=0.1.109"
+compiler_builtins = "0.1"
 alloc = { path = "./sysroot_src/library/alloc" }
 std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
 test = { path = "./sysroot_src/library/test" }
diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs
index d465ab7e506..8d9518653c5 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/build.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs
@@ -1,12 +1,13 @@
-use crate::config::{Channel, ConfigInfo};
-use crate::utils::{
-    copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir,
-};
 use std::collections::HashMap;
 use std::ffi::OsStr;
 use std::fs;
 use std::path::Path;
 
+use crate::config::{Channel, ConfigInfo};
+use crate::utils::{
+    copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir,
+};
+
 #[derive(Default)]
 struct BuildArg {
     flags: Vec<String>,
@@ -141,7 +142,14 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
         rustflags.push_str(" -Csymbol-mangling-version=v0");
     }
 
-    let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"build", &"--target", &config.target];
+    let mut args: Vec<&dyn AsRef<OsStr>> = vec![
+        &"cargo",
+        &"build",
+        &"--target",
+        &config.target,
+        &"--features",
+        &"compiler-builtins-no-f16-f128",
+    ];
 
     if config.no_default_features {
         rustflags.push_str(" -Csymbol-mangling-version=v0");
diff --git a/compiler/rustc_codegen_gcc/build_system/src/clean.rs b/compiler/rustc_codegen_gcc/build_system/src/clean.rs
index 55f55acf73e..768a78e789e 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/clean.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/clean.rs
@@ -1,8 +1,8 @@
-use crate::utils::{get_sysroot_dir, remove_file, run_command};
-
 use std::fs::remove_dir_all;
 use std::path::Path;
 
+use crate::utils::{get_sysroot_dir, remove_file, run_command};
+
 #[derive(Default)]
 enum CleanArg {
     /// `clean all`
diff --git a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs
index cbf590c0c32..e28ee873eb6 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs
@@ -1,8 +1,8 @@
+use std::path::{Path, PathBuf};
+
 use crate::config::ConfigInfo;
 use crate::utils::{git_clone, run_command_with_output};
 
-use std::path::{Path, PathBuf};
-
 fn show_usage() {
     println!(
         r#"
diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs
index bbb711c8428..15ba1612167 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/config.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs
@@ -1,14 +1,15 @@
-use crate::utils::{
-    create_dir, create_symlink, get_os_name, get_sysroot_dir, run_command_with_output,
-    rustc_version_info, split_args,
-};
 use std::collections::HashMap;
-use std::env as std_env;
 use std::ffi::OsStr;
-use std::fs;
 use std::path::{Path, PathBuf};
+use std::{env as std_env, fs};
+
+use boml::types::TomlValue;
+use boml::Toml;
 
-use boml::{types::TomlValue, Toml};
+use crate::utils::{
+    create_dir, create_symlink, get_os_name, get_sysroot_dir, run_command_with_output,
+    rustc_version_info, split_args,
+};
 
 #[derive(Default, PartialEq, Eq, Clone, Copy, Debug)]
 pub enum Channel {
diff --git a/compiler/rustc_codegen_gcc/build_system/src/fmt.rs b/compiler/rustc_codegen_gcc/build_system/src/fmt.rs
index 43644ba19b3..de310a6a30f 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/fmt.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/fmt.rs
@@ -1,7 +1,8 @@
-use crate::utils::run_command_with_output;
 use std::ffi::OsStr;
 use std::path::Path;
 
+use crate::utils::run_command_with_output;
+
 fn show_usage() {
     println!(
         r#"
diff --git a/compiler/rustc_codegen_gcc/build_system/src/main.rs b/compiler/rustc_codegen_gcc/build_system/src/main.rs
index d678fd75344..3a860e2b136 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/main.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/main.rs
@@ -1,5 +1,4 @@
-use std::env;
-use std::process;
+use std::{env, process};
 
 mod build;
 mod clean;
diff --git a/compiler/rustc_codegen_gcc/build_system/src/prepare.rs b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs
index 00aa632165e..d14639afee5 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/prepare.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs
@@ -1,12 +1,12 @@
+use std::fs;
+use std::path::{Path, PathBuf};
+
 use crate::rustc_info::get_rustc_path;
 use crate::utils::{
     cargo_install, create_dir, get_sysroot_dir, git_clone_root_dir, remove_file, run_command,
     run_command_with_output, walk_dir,
 };
 
-use std::fs;
-use std::path::{Path, PathBuf};
-
 fn prepare_libcore(
     sysroot_path: &Path,
     libgccjit12_patches: bool,
diff --git a/compiler/rustc_codegen_gcc/build_system/src/rust_tools.rs b/compiler/rustc_codegen_gcc/build_system/src/rust_tools.rs
index 242fa7ef949..105f5eebe24 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/rust_tools.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/rust_tools.rs
@@ -1,13 +1,13 @@
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::path::PathBuf;
+
 use crate::config::ConfigInfo;
 use crate::utils::{
     get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info,
     rustc_version_info,
 };
 
-use std::collections::HashMap;
-use std::ffi::OsStr;
-use std::path::PathBuf;
-
 fn args(command: &str) -> Result<Option<Vec<String>>, String> {
     // We skip the binary and the "cargo"/"rustc" option.
     if let Some("--help") = std::env::args().skip(2).next().as_deref() {
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index 06f28d13fb3..83fa8059b1a 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -1,3 +1,10 @@
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::fs::{remove_dir_all, File};
+use std::io::{BufRead, BufReader};
+use std::path::{Path, PathBuf};
+use std::str::FromStr;
+
 use crate::build;
 use crate::config::{Channel, ConfigInfo};
 use crate::utils::{
@@ -6,13 +13,6 @@ use crate::utils::{
     split_args, walk_dir,
 };
 
-use std::collections::HashMap;
-use std::ffi::OsStr;
-use std::fs::{remove_dir_all, File};
-use std::io::{BufRead, BufReader};
-use std::path::{Path, PathBuf};
-use std::str::FromStr;
-
 type Env = HashMap<String, String>;
 type Runner = fn(&Env, &TestArg) -> Result<(), String>;
 type Runners = HashMap<&'static str, (&'static str, Runner)>;
@@ -552,7 +552,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
             &"--stage",
             &"0",
             &"tests/assembly/asm",
-            &"--rustc-args",
+            &"--compiletest-rustc-args",
             &rustc_args,
         ],
         Some(&rust_dir),
@@ -1020,7 +1020,7 @@ where
             &"--stage",
             &"0",
             &format!("tests/{}", test_type),
-            &"--rustc-args",
+            &"--compiletest-rustc-args",
             &rustc_args,
         ],
         Some(&rust_path),
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 5a7ddc4cd7f..9f096e90220 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -430,6 +430,7 @@ pub enum E2<X> {
     V4,
 }
 
+#[allow(unreachable_patterns)]
 fn check_niche_behavior () {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index 21676f5dbb6..0cee05f1cea 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -1,12 +1,10 @@
-use std::path::{Path, PathBuf};
+use std::path::Path;
 
 use rustc_codegen_ssa::back::archive::{
     ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
 };
 use rustc_session::Session;
 
-use rustc_session::cstore::DllImport;
-
 pub(crate) struct ArArchiveBuilderBuilder;
 
 impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
@@ -18,10 +16,9 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
         &self,
         _sess: &Session,
         _lib_name: &str,
-        _dll_imports: &[DllImport],
-        _tmpdir: &Path,
-        _is_direct_dependency: bool,
-    ) -> PathBuf {
+        _import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        _output_path: &Path,
+    ) {
         unimplemented!("creating dll imports is not yet supported");
     }
 }
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 1da691252ab..7c135289958 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use gccjit::{LValue, RValue, ToRValue, Type};
 use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::mir::operand::OperandValue;
@@ -6,13 +8,11 @@ use rustc_codegen_ssa::traits::{
     AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef,
     InlineAsmOperandRef,
 };
-
-use rustc_middle::{bug, ty::Instance};
+use rustc_middle::bug;
+use rustc_middle::ty::Instance;
 use rustc_span::Span;
 use rustc_target::asm::*;
 
-use std::borrow::Cow;
-
 use crate::builder::Builder;
 use crate::callee::get_fn;
 use crate::context::CodegenCx;
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index 27f21107eda..5fdf2680aac 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -9,8 +9,9 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty;
 use rustc_span::symbol::sym;
 
+use crate::context::CodegenCx;
+use crate::errors::TiedTargetFeatures;
 use crate::gcc_util::{check_tied_features, to_gcc_features};
-use crate::{context::CodegenCx, errors::TiedTargetFeatures};
 
 /// Get GCC attribute for the provided inline heuristic.
 #[cfg(feature = "master")]
@@ -74,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
     let function_features = codegen_fn_attrs
         .target_features
         .iter()
-        .map(|features| features.as_str())
+        .map(|features| features.name.as_str())
         .collect::<Vec<&str>>();
 
     if let Some(features) = check_tied_features(
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index be149ffe5a1..4940a7fa205 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -19,8 +19,7 @@ use rustc_target::spec::PanicStrategy;
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
-use crate::{gcc_util, new_context, LockedTargetInfo};
-use crate::{GccContext, SyncContext};
+use crate::{gcc_util, new_context, GccContext, LockedTargetInfo, SyncContext};
 
 #[cfg(feature = "master")]
 pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility {
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index b9e4bd79fe1..47b378cc1cd 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -28,9 +28,8 @@ use rustc_middle::ty::layout::{
 use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
-use rustc_target::abi::{
-    self, call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange,
-};
+use rustc_target::abi::call::FnAbi;
+use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
 
 use crate::common::{type_is_pointer, SignType, TypeReflection};
@@ -1128,6 +1127,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         self.llbb().add_assignment(self.location, aligned_destination, val);
         // TODO(antoyo): handle align and flags.
         // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
+        // When adding support for NONTEMPORAL, make sure to not just emit MOVNT on x86; see the
+        // LLVM backend for details.
         self.cx.context.new_rvalue_zero(self.type_i32())
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 70f0dc37e39..dca6b6494f9 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -1,5 +1,4 @@
-use gccjit::LValue;
-use gccjit::{RValue, ToRValue, Type};
+use gccjit::{LValue, RValue, ToRValue, Type};
 use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods};
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::mir::Mutability;
@@ -161,6 +160,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
     }
 
+    fn const_vector(&self, values: &[RValue<'gcc>]) -> RValue<'gcc> {
+        let typ = self.type_vector(values[0].get_type(), values.len() as u64);
+        self.context.new_rvalue_from_vector(None, typ, values)
+    }
+
     fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
         // TODO(antoyo)
         None
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index ba7e08e33ef..e5673cddc4a 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -3,14 +3,13 @@ use gccjit::{FnAttribute, VarAttribute, Visibility};
 use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type};
 use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, StaticMethods};
 use rustc_hir::def::DefKind;
-use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
     self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar,
 };
-use rustc_middle::span_bug;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Instance};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
 
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 86a5000a723..e330102fbd8 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -6,8 +6,7 @@ use gccjit::{
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::errors as ssa_errors;
 use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods};
-use rustc_data_structures::base_n::ToBaseN;
-use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
+use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::span_bug;
@@ -17,10 +16,10 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_session::Session;
-use rustc_span::{source_map::respan, Span, DUMMY_SP};
-use rustc_target::abi::{
-    call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
-};
+use rustc_span::source_map::respan;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::call::FnAbi;
+use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
 use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
 
 use crate::callee::get_fn;
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index 3d9ea278a63..d770da5a8c4 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
 use gccjit::{Location, RValue};
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
 use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
@@ -10,7 +12,6 @@ use rustc_session::config::DebugInfo;
 use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Size;
-use std::ops::Range;
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 53877e8ff7f..5308ccdb614 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -1,11 +1,10 @@
 #[cfg(feature = "master")]
 use gccjit::Context;
-use smallvec::{smallvec, SmallVec};
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
 use rustc_session::Session;
 use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
+use smallvec::{smallvec, SmallVec};
 
 use crate::errors::{
     PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
@@ -66,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
 
             let feature = backend_feature_name(s)?;
             // Warn against use of GCC specific feature names on the CLI.
-            if diagnostics && !supported_features.iter().any(|&(v, _)| v == feature) {
-                let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
+            if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
+                let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| {
                     let gcc_features = to_gcc_features(sess, rust_feature);
                     if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) {
                         Some(rust_feature)
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index e4c5eb91373..92d5c1cbbb8 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -6,18 +6,13 @@ use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, T
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp};
 use rustc_middle::ty::{ParamEnv, Ty};
-use rustc_target::abi::{
-    call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode},
-    Endian,
-};
+use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
+use rustc_target::abi::Endian;
 use rustc_target::spec;
 
-use crate::builder::ToGccComp;
-use crate::{
-    builder::Builder,
-    common::{SignType, TypeReflection},
-    context::CodegenCx,
-};
+use crate::builder::{Builder, ToGccComp};
+use crate::common::{SignType, TypeReflection};
+use crate::context::CodegenCx;
 
 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
     pub fn gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -266,7 +261,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         lhs: <Self as BackendTypes>::Value,
         rhs: <Self as BackendTypes>::Value,
     ) -> (<Self as BackendTypes>::Value, <Self as BackendTypes>::Value) {
-        use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*};
+        use rustc_middle::ty::IntTy::*;
+        use rustc_middle::ty::UintTy::*;
+        use rustc_middle::ty::{Int, Uint};
 
         let new_kind = match *typ.kind() {
             Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
index a1270482219..554e57250e6 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
@@ -3,7 +3,8 @@ use std::borrow::Cow;
 use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp};
 use rustc_codegen_ssa::traits::BuilderMethods;
 
-use crate::{builder::Builder, context::CodegenCx};
+use crate::builder::Builder;
+use crate::context::CodegenCx;
 
 pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
     builder: &Builder<'a, 'gcc, 'tcx>,
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index ba214a9c24c..8da1df3be15 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -1,10 +1,8 @@
 use std::iter::FromIterator;
 
-use gccjit::ToRValue;
-use gccjit::{BinaryOp, RValue, Type};
+use gccjit::{BinaryOp, RValue, ToRValue, Type};
 #[cfg(feature = "master")]
 use gccjit::{ComparisonOp, UnaryOp};
-
 use rustc_codegen_ssa::base::compare_simd_types;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 #[cfg(feature = "master")]
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 1132b0cd2f5..94f016234f9 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -79,14 +79,11 @@ use std::ops::Deref;
 use std::sync::atomic::AtomicBool;
 #[cfg(not(feature = "master"))]
 use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::sync::Mutex;
+use std::sync::{Arc, Mutex};
 
-use back::lto::ThinBuffer;
-use back::lto::ThinData;
+use back::lto::{ThinBuffer, ThinData};
 use errors::LTONotSupported;
-use gccjit::CType;
-use gccjit::{Context, OptimizationLevel};
+use gccjit::{CType, Context, OptimizationLevel};
 #[cfg(feature = "master")]
 use gccjit::{TargetInfo, Version};
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -489,7 +486,7 @@ pub fn target_features(
     sess.target
         .supported_target_features()
         .iter()
-        .filter_map(|&(feature, gate)| {
+        .filter_map(|&(feature, gate, _)| {
             if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
                 Some(feature)
             } else {
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index 44657ad4f6e..e6b22d51871 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -9,10 +9,9 @@ use rustc_middle::mir::mono::{Linkage, Visibility};
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 
-use crate::attributes;
-use crate::base;
 use crate::context::CodegenCx;
 use crate::type_of::LayoutGccExt;
+use crate::{attributes, base};
 
 impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     #[cfg_attr(not(feature = "master"), allow(unused_variables))]
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index bb5045ec872..dad4722d620 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -12,7 +12,7 @@ bitflags = "2.4.1"
 itertools = "0.12"
 libc = "0.2"
 measureme = "11"
-object = { version = "0.32.0", default-features = false, features = ["std", "read"] }
+object = { version = "0.36.2", default-features = false, features = ["std", "read"] }
 rustc-demangle = "0.1.21"
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 1c126e79762..267da9325c3 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,23 +1,13 @@
 codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
 
-codegen_llvm_dlltool_fail_import_library =
-    Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
-    {$stdout}
-    {$stderr}
-
 codegen_llvm_dynamic_linking_with_lto =
     cannot prefer dynamic linking when performing LTO
     .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
 
-codegen_llvm_error_calling_dlltool =
-    Error calling dlltool '{$dlltool_path}': {$error}
 
 codegen_llvm_error_creating_import_library =
     Error creating import library for {$lib_name}: {$error}
 
-codegen_llvm_error_writing_def_file =
-    Error writing .DEF file: {$error}
-
 codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
 
 codegen_llvm_from_llvm_diag = {$message}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index d034f9b5256..5ff580e295a 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -1,30 +1,29 @@
-use crate::attributes;
-use crate::builder::Builder;
-use crate::context::CodegenCx;
-use crate::llvm::{self, Attribute, AttributePlace};
-use crate::llvm_util;
-use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
-use crate::value::Value;
+use std::cmp;
 
+use libc::c_uint;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::MemFlags;
-use rustc_middle::bug;
 use rustc_middle::ty::layout::LayoutOf;
 pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use rustc_middle::ty::Ty;
+use rustc_middle::{bug, ty};
 use rustc_session::config;
 pub use rustc_target::abi::call::*;
 use rustc_target::abi::{self, HasDataLayout, Int, Size};
 pub use rustc_target::spec::abi::Abi;
 use rustc_target::spec::SanitizerSet;
-
-use libc::c_uint;
 use smallvec::SmallVec;
 
-use std::cmp;
+use crate::attributes::llfn_attrs_from_instance;
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::llvm::{self, Attribute, AttributePlace};
+use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
+use crate::value::Value;
+use crate::{attributes, llvm_util};
 
 pub trait ArgAttributesExt {
     fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
@@ -121,8 +120,10 @@ impl LlvmType for Reg {
         match self.kind {
             RegKind::Integer => cx.type_ix(self.size.bits()),
             RegKind::Float => match self.size.bits() {
+                16 => cx.type_f16(),
                 32 => cx.type_f32(),
                 64 => cx.type_f64(),
+                128 => cx.type_f128(),
                 _ => bug!("unsupported float: {:?}", self),
             },
             RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
@@ -310,7 +311,16 @@ pub trait FnAbiLlvmExt<'ll, 'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
-    fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
+
+    /// Apply attributes to a function declaration/definition.
+    fn apply_attrs_llfn(
+        &self,
+        cx: &CodegenCx<'ll, 'tcx>,
+        llfn: &'ll Value,
+        instance: Option<ty::Instance<'tcx>>,
+    );
+
+    /// Apply attributes to a function call.
     fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value);
 }
 
@@ -396,7 +406,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         self.conv.into()
     }
 
-    fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
+    fn apply_attrs_llfn(
+        &self,
+        cx: &CodegenCx<'ll, 'tcx>,
+        llfn: &'ll Value,
+        instance: Option<ty::Instance<'tcx>>,
+    ) {
         let mut func_attrs = SmallVec::<[_; 3]>::new();
         if self.ret.layout.abi.is_uninhabited() {
             func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
@@ -415,9 +430,32 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             i += 1;
             i - 1
         };
+
+        let apply_range_attr = |idx: AttributePlace, scalar: rustc_target::abi::Scalar| {
+            if cx.sess().opts.optimize != config::OptLevel::No
+                && llvm_util::get_version() >= (19, 0, 0)
+                && matches!(scalar.primitive(), Int(..))
+                // If the value is a boolean, the range is 0..2 and that ultimately
+                // become 0..0 when the type becomes i1, which would be rejected
+                // by the LLVM verifier.
+                && !scalar.is_bool()
+                // LLVM also rejects full range.
+                && !scalar.is_always_valid(cx)
+            {
+                attributes::apply_to_llfn(
+                    llfn,
+                    idx,
+                    &[llvm::CreateRangeAttr(cx.llcx, scalar.size(cx), scalar.valid_range(cx))],
+                );
+            }
+        };
+
         match &self.ret.mode {
             PassMode::Direct(attrs) => {
                 attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
+                if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
+                    apply_range_attr(llvm::AttributePlace::ReturnValue, scalar);
+                }
             }
             PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
                 assert!(!on_stack);
@@ -456,8 +494,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     );
                     attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
                 }
-                PassMode::Direct(attrs)
-                | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
+                PassMode::Direct(attrs) => {
+                    let i = apply(attrs);
+                    if let abi::Abi::Scalar(scalar) = arg.layout.abi {
+                        apply_range_attr(llvm::AttributePlace::Argument(i), scalar);
+                    }
+                }
+                PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
                     apply(attrs);
                 }
                 PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
@@ -466,8 +509,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     apply(meta_attrs);
                 }
                 PassMode::Pair(a, b) => {
-                    apply(a);
-                    apply(b);
+                    let i = apply(a);
+                    let ii = apply(b);
+                    if let abi::Abi::ScalarPair(scalar_a, scalar_b) = arg.layout.abi {
+                        apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
+                        apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b);
+                    }
                 }
                 PassMode::Cast { cast, pad_i32 } => {
                     if *pad_i32 {
@@ -477,6 +524,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                 }
             }
         }
+
+        // If the declaration has an associated instance, compute extra attributes based on that.
+        if let Some(instance) = instance {
+            llfn_attrs_from_instance(cx, llfn, instance);
+        }
     }
 
     fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
@@ -517,15 +569,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             }
             _ => {}
         }
-        if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
-            // If the value is a boolean, the range is 0..2 and that ultimately
-            // become 0..0 when the type becomes i1, which would be rejected
-            // by the LLVM verifier.
-            if let Int(..) = scalar.primitive() {
-                if !scalar.is_bool() && !scalar.is_always_valid(bx) {
-                    bx.range_metadata(callsite, scalar.valid_range(bx));
-                }
-            }
+        if bx.cx.sess().opts.optimize != config::OptLevel::No
+                && llvm_util::get_version() < (19, 0, 0)
+                && let abi::Abi::Scalar(scalar) = self.ret.layout.abi
+                && matches!(scalar.primitive(), Int(..))
+                // If the value is a boolean, the range is 0..2 and that ultimately
+                // become 0..0 when the type becomes i1, which would be rejected
+                // by the LLVM verifier.
+                && !scalar.is_bool()
+                // LLVM also rejects full range.
+                && !scalar.is_always_valid(bx)
+        {
+            bx.range_metadata(callsite, scalar.valid_range(bx));
         }
         for arg in self.args.iter() {
             match &arg.mode {
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 5969d9b9144..8fb31082793 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -1,4 +1,3 @@
-use crate::attributes;
 use libc::c_uint;
 use rustc_ast::expand::allocator::{
     alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
@@ -8,9 +7,8 @@ use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
 
-use crate::debuginfo;
 use crate::llvm::{self, Context, False, Module, True, Type};
-use crate::ModuleLlvm;
+use crate::{attributes, debuginfo, ModuleLlvm};
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 597ebd97365..f931698c38f 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -1,25 +1,26 @@
-use crate::attributes;
-use crate::builder::Builder;
-use crate::common::Funclet;
-use crate::context::CodegenCx;
-use crate::llvm;
-use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
-use crate::value::Value;
+use std::assert_matches::assert_matches;
 
+use libc::{c_char, c_uint};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::mir::operand::OperandValue;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::{bug, span_bug, ty::Instance};
+use rustc_middle::ty::Instance;
+use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, Pos, Span, Symbol};
 use rustc_target::abi::*;
 use rustc_target::asm::*;
+use smallvec::SmallVec;
 use tracing::debug;
 
-use libc::{c_char, c_uint};
-use smallvec::SmallVec;
+use crate::builder::Builder;
+use crate::common::Funclet;
+use crate::context::CodegenCx;
+use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
+use crate::value::Value;
+use crate::{attributes, llvm};
 
 impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
     fn codegen_inline_asm(
@@ -90,7 +91,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                         // if the target feature needed by the register class is
                         // disabled. This is necessary otherwise LLVM will try
                         // to actually allocate a register for the dummy output.
-                        assert!(matches!(reg, InlineAsmRegOrRegClass::Reg(_)));
+                        assert_matches!(reg, InlineAsmRegOrRegClass::Reg(_));
                         clobbers.push(format!("~{}", reg_to_llvm(reg, None)));
                         continue;
                     } else {
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 3877460fcdb..fde95104093 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -1,23 +1,21 @@
 //! Set and unset common attributes on LLVM values.
 
+pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::config::{FunctionReturn, OptLevel};
+use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
 use rustc_span::symbol::sym;
 use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 use smallvec::SmallVec;
 
-use crate::attributes;
+use crate::context::CodegenCx;
 use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable};
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
-use crate::llvm_util;
-pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
-
-use crate::context::CodegenCx;
 use crate::value::Value;
+use crate::{attributes, llvm_util};
 
 pub fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
     if !attrs.is_empty() {
@@ -326,9 +324,10 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
     llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
 }
 
+/// Helper for `FnAbi::apply_attrs_llfn`:
 /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
 /// attributes.
-pub fn from_fn_attrs<'ll, 'tcx>(
+pub fn llfn_attrs_from_instance<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     llfn: &'ll Value,
     instance: ty::Instance<'tcx>,
@@ -407,8 +406,33 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         // And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules.
         // Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768
         to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
-        // Need this for AArch64.
-        to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
+        if llvm_util::get_version() < (19, 0, 0) {
+            // Prior to LLVM 19, branch-target-enforcement was disabled by setting the attribute to
+            // the string "false". Now it is disabled by absence of the attribute.
+            to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
+        }
+    } else if llvm_util::get_version() >= (19, 0, 0) {
+        // For non-naked functions, set branch protection attributes on aarch64.
+        if let Some(BranchProtection { bti, pac_ret }) =
+            cx.sess().opts.unstable_opts.branch_protection
+        {
+            assert!(cx.sess().target.arch == "aarch64");
+            if bti {
+                to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
+            }
+            if let Some(PacRet { leaf, key }) = pac_ret {
+                to_add.push(llvm::CreateAttrStringValue(
+                    cx.llcx,
+                    "sign-return-address",
+                    if leaf { "all" } else { "non-leaf" },
+                ));
+                to_add.push(llvm::CreateAttrStringValue(
+                    cx.llcx,
+                    "sign-return-address-key",
+                    if key == PAuthKey::A { "a_key" } else { "b_key" },
+                ));
+            }
+        }
     }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
         || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
@@ -473,7 +497,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     to_add.extend(tune_cpu_attr(cx));
 
     let function_features =
-        codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
+        codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
 
     if let Some(f) = llvm_util::check_tied_features(
         cx.tcx.sess,
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index f46c6b1c498..a2ab19ac800 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -1,27 +1,21 @@
 //! A helper class for dealing with static archives
 
-use std::env;
-use std::ffi::{c_char, c_void, CStr, CString, OsString};
-use std::io;
-use std::mem;
+use std::ffi::{c_char, c_void, CStr, CString};
 use std::path::{Path, PathBuf};
-use std::ptr;
-use std::str;
+use std::{io, mem, ptr, str};
 
-use crate::common;
-use crate::errors::{
-    DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
-};
-use crate::llvm::archive_ro::{ArchiveRO, Child};
-use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::{
-    try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
-    ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
+    create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder,
+    ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind,
+    DEFAULT_OBJECT_READER,
 };
+use rustc_codegen_ssa::common;
+use rustc_session::Session;
 use tracing::trace;
 
-use rustc_session::cstore::DllImport;
-use rustc_session::Session;
+use crate::errors::ErrorCreatingImportLibrary;
+use crate::llvm::archive_ro::{ArchiveRO, Child};
+use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 
 /// Helper for adding many files to an archive.
 #[must_use = "must call build() to finish building the archive"]
@@ -101,7 +95,9 @@ impl<'a> ArchiveBuilder for LlvmArchiveBuilder<'a> {
     fn build(mut self: Box<Self>, output: &Path) -> bool {
         match self.build_with_llvm(output) {
             Ok(any_members) => any_members,
-            Err(e) => self.sess.dcx().emit_fatal(ArchiveBuildFailure { error: e }),
+            Err(error) => {
+                self.sess.dcx().emit_fatal(ArchiveBuildFailure { path: output.to_owned(), error })
+            }
         }
     }
 }
@@ -123,116 +119,21 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
         &self,
         sess: &Session,
         lib_name: &str,
-        dll_imports: &[DllImport],
-        tmpdir: &Path,
-        is_direct_dependency: bool,
-    ) -> PathBuf {
-        let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
-        let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));
-
-        let target = &sess.target;
-        let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
-
-        let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
-            .iter()
-            .map(|import: &DllImport| {
-                if sess.target.arch == "x86" {
-                    (
-                        common::i686_decorated_name(import, mingw_gnu_toolchain, false),
-                        import.ordinal(),
-                    )
-                } else {
-                    (import.name.to_string(), import.ordinal())
-                }
-            })
-            .collect();
-
-        if mingw_gnu_toolchain {
+        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        output_path: &Path,
+    ) {
+        if common::is_mingw_gnu_toolchain(&sess.target) {
             // The binutils linker used on -windows-gnu targets cannot read the import
             // libraries generated by LLVM: in our attempts, the linker produced an .EXE
             // that loaded but crashed with an AV upon calling one of the imported
             // functions. Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
-            let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def"));
-
-            let def_file_content = format!(
-                "EXPORTS\n{}",
-                import_name_and_ordinal_vector
-                    .into_iter()
-                    .map(|(name, ordinal)| {
-                        match ordinal {
-                            Some(n) => format!("{name} @{n} NONAME"),
-                            None => name,
-                        }
-                    })
-                    .collect::<Vec<String>>()
-                    .join("\n")
+            create_mingw_dll_import_lib(
+                sess,
+                lib_name,
+                import_name_and_ordinal_vector,
+                output_path,
             );
-
-            match std::fs::write(&def_file_path, def_file_content) {
-                Ok(_) => {}
-                Err(e) => {
-                    sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
-                }
-            };
-
-            // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
-            // able to control the *exact* spelling of each of the symbols that are being imported:
-            // hence we don't want `dlltool` adding leading underscores automatically.
-            let dlltool = find_binutils_dlltool(sess);
-            let temp_prefix = {
-                let mut path = PathBuf::from(&output_path);
-                path.pop();
-                path.push(lib_name);
-                path
-            };
-            // dlltool target architecture args from:
-            // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
-            let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
-                "x86_64" => ("i386:x86-64", "--64"),
-                "x86" => ("i386", "--32"),
-                "aarch64" => ("arm64", "--64"),
-                "arm" => ("arm", "--32"),
-                _ => panic!("unsupported arch {}", sess.target.arch),
-            };
-            let mut dlltool_cmd = std::process::Command::new(&dlltool);
-            dlltool_cmd
-                .arg("-d")
-                .arg(def_file_path)
-                .arg("-D")
-                .arg(lib_name)
-                .arg("-l")
-                .arg(&output_path)
-                .arg("-m")
-                .arg(dlltool_target_arch)
-                .arg("-f")
-                .arg(dlltool_target_bitness)
-                .arg("--no-leading-underscore")
-                .arg("--temp-prefix")
-                .arg(temp_prefix);
-
-            match dlltool_cmd.output() {
-                Err(e) => {
-                    sess.dcx().emit_fatal(ErrorCallingDllTool {
-                        dlltool_path: dlltool.to_string_lossy(),
-                        error: e,
-                    });
-                }
-                // dlltool returns '0' on failure, so check for error output instead.
-                Ok(output) if !output.stderr.is_empty() => {
-                    sess.dcx().emit_fatal(DlltoolFailImportLibrary {
-                        dlltool_path: dlltool.to_string_lossy(),
-                        dlltool_args: dlltool_cmd
-                            .get_args()
-                            .map(|arg| arg.to_string_lossy())
-                            .collect::<Vec<_>>()
-                            .join(" "),
-                        stdout: String::from_utf8_lossy(&output.stdout),
-                        stderr: String::from_utf8_lossy(&output.stderr),
-                    })
-                }
-                _ => {}
-            }
         } else {
             // we've checked for \0 characters in the library name already
             let dll_name_z = CString::new(lib_name).unwrap();
@@ -244,9 +145,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             trace!("  output_path {}", output_path.display());
             trace!(
                 "  import names: {}",
-                dll_imports
+                import_name_and_ordinal_vector
                     .iter()
-                    .map(|import| import.name.to_string())
+                    .map(|(name, _ordinal)| name.clone())
                     .collect::<Vec<_>>()
                     .join(", "),
             );
@@ -283,9 +184,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                     error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
                 });
             }
-        };
-
-        output_path
+        }
     }
 }
 
@@ -459,39 +358,3 @@ impl<'a> LlvmArchiveBuilder<'a> {
 fn string_to_io_error(s: String) -> io::Error {
     io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
 }
-
-fn find_binutils_dlltool(sess: &Session) -> OsString {
-    assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
-    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
-        return dlltool_path.clone().into_os_string();
-    }
-
-    let tool_name: OsString = if sess.host.options.is_like_windows {
-        // If we're compiling on Windows, always use "dlltool.exe".
-        "dlltool.exe"
-    } else {
-        // On other platforms, use the architecture-specific name.
-        match sess.target.arch.as_ref() {
-            "x86_64" => "x86_64-w64-mingw32-dlltool",
-            "x86" => "i686-w64-mingw32-dlltool",
-            "aarch64" => "aarch64-w64-mingw32-dlltool",
-
-            // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
-            _ => "dlltool",
-        }
-    }
-    .into();
-
-    // NOTE: it's not clear how useful it is to explicitly search PATH.
-    for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
-        let full_path = dir.join(&tool_name);
-        if full_path.is_file() {
-            return full_path.into_os_string();
-        }
-    }
-
-    // The user didn't specify the location of the dlltool binary, and we weren't able
-    // to find the appropriate one on the PATH. Just return the name of the tool
-    // and let the invocation fail with a hopefully useful error message.
-    tool_name
-}
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index aef672631c8..f68155f523a 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,11 +1,11 @@
-use crate::back::write::{
-    self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers,
-};
-use crate::errors::{
-    DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
-};
-use crate::llvm::{self, build_string};
-use crate::{LlvmCodegenBackend, ModuleLlvm};
+use std::collections::BTreeMap;
+use std::ffi::{CStr, CString};
+use std::fs::File;
+use std::mem::ManuallyDrop;
+use std::path::Path;
+use std::sync::Arc;
+use std::{io, iter, slice};
+
 use object::read::archive::ArchiveFile;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
@@ -22,15 +22,14 @@ use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel
 use rustc_session::config::{self, CrateType, Lto};
 use tracing::{debug, info};
 
-use std::collections::BTreeMap;
-use std::ffi::{CStr, CString};
-use std::fs::File;
-use std::io;
-use std::iter;
-use std::mem::ManuallyDrop;
-use std::path::Path;
-use std::slice;
-use std::sync::Arc;
+use crate::back::write::{
+    self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers,
+};
+use crate::errors::{
+    DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
+};
+use crate::llvm::{self, build_string};
+use crate::{LlvmCodegenBackend, ModuleLlvm};
 
 /// We keep track of the computed LTO cache keys from the previous
 /// session to determine which CGUs we can reuse.
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index b72636a6224..681ac75c877 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -1,13 +1,12 @@
-use std::{
-    ffi::{c_char, CStr},
-    marker::PhantomData,
-    ops::Deref,
-    ptr::NonNull,
-};
+use std::ffi::{c_char, CStr};
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::ptr::NonNull;
 
 use rustc_data_structures::small_c_str::SmallCStr;
 
-use crate::{errors::LlvmError, llvm};
+use crate::errors::LlvmError;
+use crate::llvm;
 
 /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
 /// Not cloneable as there is no clone function for llvm::TargetMachine.
diff --git a/compiler/rustc_codegen_llvm/src/back/profiling.rs b/compiler/rustc_codegen_llvm/src/back/profiling.rs
index 2eee9f8c5a3..26fb4a96f84 100644
--- a/compiler/rustc_codegen_llvm/src/back/profiling.rs
+++ b/compiler/rustc_codegen_llvm/src/back/profiling.rs
@@ -1,9 +1,11 @@
-use measureme::{event_id::SEPARATOR_BYTE, EventId, StringComponent, StringId};
-use rustc_data_structures::profiling::{SelfProfiler, TimingGuard};
 use std::ffi::{c_void, CStr};
 use std::os::raw::c_char;
 use std::sync::Arc;
 
+use measureme::event_id::SEPARATOR_BYTE;
+use measureme::{EventId, StringComponent, StringId};
+use rustc_data_structures::profiling::{SelfProfiler, TimingGuard};
+
 fn llvm_args_to_string_id(profiler: &SelfProfiler, pass_name: &str, ir_name: &str) -> EventId {
     let pass_name = profiler.get_or_alloc_cached_string(pass_name);
     let mut components = vec![StringComponent::Ref(pass_name)];
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index ddd52e80edf..a1f2433ab6f 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1,19 +1,10 @@
-use crate::back::lto::ThinBuffer;
-use crate::back::owned_target_machine::OwnedTargetMachine;
-use crate::back::profiling::{
-    selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
-};
-use crate::base;
-use crate::common;
-use crate::errors::{
-    CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
-    WithLlvmError, WriteBytecode,
-};
-use crate::llvm::{self, DiagnosticInfo, PassManager};
-use crate::llvm_util;
-use crate::type_::Type;
-use crate::LlvmCodegenBackend;
-use crate::ModuleLlvm;
+use std::ffi::CString;
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+use std::{fs, slice, str};
+
+use libc::{c_char, c_int, c_void, size_t};
 use llvm::{
     LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
 };
@@ -29,23 +20,28 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{DiagCtxtHandle, FatalError, Level};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes};
-use rustc_session::config::{RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath};
+use rustc_session::config::{
+    self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath,
+};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
 use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
 use tracing::debug;
 
+use crate::back::lto::ThinBuffer;
+use crate::back::owned_target_machine::OwnedTargetMachine;
+use crate::back::profiling::{
+    selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
+};
+use crate::errors::{
+    CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
+    WithLlvmError, WriteBytecode,
+};
 use crate::llvm::diagnostic::OptimizationDiagnosticKind;
-use libc::{c_char, c_int, c_void, size_t};
-use std::ffi::CString;
-use std::fs;
-use std::io::{self, Write};
-use std::path::{Path, PathBuf};
-use std::slice;
-use std::str;
-use std::sync::Arc;
+use crate::llvm::{self, DiagnosticInfo, PassManager};
+use crate::type_::Type;
+use crate::{base, common, llvm_util, LlvmCodegenBackend, ModuleLlvm};
 
 pub fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> FatalError {
     match llvm::last_error() {
@@ -99,11 +95,14 @@ pub fn write_output_file<'ll>(
     }
 }
 
-pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
+pub fn create_informational_target_machine(
+    sess: &Session,
+    only_base_features: bool,
+) -> OwnedTargetMachine {
     let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
     // Can't use query system here quite yet because this function is invoked before the query
     // system/tcx is set up.
-    let features = llvm_util::global_llvm_features(sess, false);
+    let features = llvm_util::global_llvm_features(sess, false, only_base_features);
     target_machine_factory(sess, config::OptLevel::No, &features)(config)
         .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
 }
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 5dc271ccddb..e8236b45c89 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -11,13 +11,7 @@
 //! [`Ty`]: rustc_middle::ty::Ty
 //! [`val_ty`]: crate::common::val_ty
 
-use super::ModuleLlvm;
-
-use crate::attributes;
-use crate::builder::Builder;
-use crate::context::CodegenCx;
-use crate::llvm;
-use crate::value::Value;
+use std::time::Instant;
 
 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
 use rustc_codegen_ssa::mono_item::MonoItemExt;
@@ -32,7 +26,11 @@ use rustc_session::config::DebugInfo;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::SanitizerSet;
 
-use std::time::Instant;
+use super::ModuleLlvm;
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::value::Value;
+use crate::{attributes, llvm};
 
 pub struct ValueIter<'ll> {
     cur: Option<&'ll Value>,
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 72ff9ea118e..cc081f29e12 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1,12 +1,7 @@
-use crate::abi::FnAbiLlvmExt;
-use crate::attributes;
-use crate::common::Funclet;
-use crate::context::CodegenCx;
-use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True};
-use crate::llvm_util;
-use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
-use crate::value::Value;
+use std::borrow::Cow;
+use std::ops::Deref;
+use std::{iter, ptr};
+
 use libc::{c_char, c_uint};
 use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
@@ -17,21 +12,28 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
+    TyAndLayout,
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_sanitizers::{cfi, kcfi};
 use rustc_session::config::OptLevel;
 use rustc_span::Span;
-use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
+use rustc_target::abi::call::FnAbi;
+use rustc_target::abi::{self, Align, Size, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
 use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::iter;
-use std::ops::Deref;
-use std::ptr;
 use tracing::{debug, instrument};
 
+use crate::abi::FnAbiLlvmExt;
+use crate::common::Funclet;
+use crate::context::CodegenCx;
+use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True};
+use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
+use crate::value::Value;
+use crate::{attributes, llvm_util};
+
 // All Builders must have an llfn associated with them
 #[must_use]
 pub struct Builder<'a, 'll, 'tcx> {
@@ -390,8 +392,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         lhs: Self::Value,
         rhs: Self::Value,
     ) -> (Self::Value, Self::Value) {
+        use rustc_middle::ty::IntTy::*;
+        use rustc_middle::ty::UintTy::*;
         use rustc_middle::ty::{Int, Uint};
-        use rustc_middle::ty::{IntTy::*, UintTy::*};
 
         let new_kind = match ty.kind() {
             Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
@@ -529,7 +532,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     #[instrument(level = "trace", skip(self))]
     fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> {
         if place.layout.is_unsized() {
-            let tail = self.tcx.struct_tail_with_normalize(place.layout.ty, |ty| ty, || {});
+            let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.param_env());
             if matches!(tail.kind(), ty::Foreign(..)) {
                 // Unsized locals and, at least conceptually, even unsized arguments must be copied
                 // around, which requires dynamically determining their size. Therefore, we cannot
@@ -725,13 +728,32 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 llvm::LLVMSetVolatile(store, llvm::True);
             }
             if flags.contains(MemFlags::NONTEMPORAL) {
-                // According to LLVM [1] building a nontemporal store must
-                // *always* point to a metadata value of the integer 1.
-                //
-                // [1]: https://llvm.org/docs/LangRef.html#store-instruction
-                let one = self.cx.const_i32(1);
-                let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
-                llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
+                // Make sure that the current target architectures supports "sane" non-temporal
+                // stores, i.e., non-temporal stores that are equivalent to regular stores except
+                // for performance. LLVM doesn't seem to care about this, and will happily treat
+                // `!nontemporal` stores as-if they were normal stores (for reordering optimizations
+                // etc) even on x86, despite later lowering them to MOVNT which do *not* behave like
+                // regular stores but require special fences.
+                // So we keep a list of architectures where `!nontemporal` is known to be truly just
+                // a hint, and use regular stores everywhere else.
+                // (In the future, we could alternatively ensure that an sfence gets emitted after a sequence of movnt
+                // before any kind of synchronizing operation. But it's not clear how to do that with LLVM.)
+                // For more context, see <https://github.com/rust-lang/rust/issues/114582> and
+                // <https://github.com/llvm/llvm-project/issues/64521>.
+                const WELL_BEHAVED_NONTEMPORAL_ARCHS: &[&str] =
+                    &["aarch64", "arm", "riscv32", "riscv64"];
+
+                let use_nontemporal =
+                    WELL_BEHAVED_NONTEMPORAL_ARCHS.contains(&&*self.cx.tcx.sess.target.arch);
+                if use_nontemporal {
+                    // According to LLVM [1] building a nontemporal store must
+                    // *always* point to a metadata value of the integer 1.
+                    //
+                    // [1]: https://llvm.org/docs/LangRef.html#store-instruction
+                    let one = self.cx.const_i32(1);
+                    let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
+                    llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
+                }
             }
             store
         }
@@ -1353,6 +1375,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         }
     }
 
+    pub fn set_unpredictable(&mut self, inst: &'ll Value) {
+        unsafe {
+            llvm::LLVMSetMetadata(
+                inst,
+                llvm::MD_unpredictable as c_uint,
+                llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0),
+            );
+        }
+    }
+
     pub fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
         unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
     }
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 659c6ae0d86..663c5be46e5 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -4,16 +4,15 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use crate::attributes;
-use crate::common;
-use crate::context::CodegenCx;
-use crate::llvm;
-use crate::value::Value;
-
+use rustc_codegen_ssa::common;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 use tracing::debug;
 
+use crate::context::CodegenCx;
+use crate::llvm;
+use crate::value::Value;
+
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
 ///
@@ -48,7 +47,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
     } else {
         let instance_def_id = instance.def_id();
         let llfn = if tcx.sess.target.arch == "x86"
-            && let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
+            && let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
         {
             // Fix for https://github.com/rust-lang/rust/issues/104453
             // On x86 Windows, LLVM uses 'L' as the prefix for any private
@@ -79,8 +78,6 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
         };
         debug!("get_fn: not casting pointer!");
 
-        attributes::from_fn_attrs(cx, llfn, instance);
-
         // Apply an appropriate linkage/visibility value to our item that we
         // just declared.
         //
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index fe64649cf70..a3997900184 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -1,11 +1,6 @@
 //! Code that is useful in various codegen modules.
 
-use crate::consts::const_alloc_to_llvm;
-pub use crate::context::CodegenCx;
-use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, OperandBundleDef, True};
-use crate::type_::Type;
-use crate::value::Value;
-
+use libc::{c_char, c_uint};
 use rustc_ast::Mutability;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
@@ -13,14 +8,16 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
+use rustc_session::cstore::DllImport;
 use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer};
-use rustc_target::spec::Target;
-
-use libc::{c_char, c_uint};
-use std::fmt::Write;
 use tracing::debug;
 
+use crate::consts::const_alloc_to_llvm;
+pub use crate::context::CodegenCx;
+use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, OperandBundleDef, True};
+use crate::type_::Type;
+use crate::value::Value;
+
 /*
 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
 *
@@ -100,11 +97,6 @@ impl<'ll> CodegenCx<'ll, '_> {
         unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
     }
 
-    pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
-        let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
-        unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
-    }
-
     pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
         bytes_in_context(self.llcx, bytes)
     }
@@ -224,6 +216,11 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         struct_in_context(self.llcx, elts, packed)
     }
 
+    fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
+        let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
+        unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
+    }
+
     fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
         try_as_const_integral(v).and_then(|v| unsafe {
             let mut i = 0u64;
@@ -379,64 +376,3 @@ pub(crate) fn get_dllimport<'tcx>(
     tcx.native_library(id)
         .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
 }
-
-pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool {
-    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
-}
-
-pub(crate) fn i686_decorated_name(
-    dll_import: &DllImport,
-    mingw: bool,
-    disable_name_mangling: bool,
-) -> String {
-    let name = dll_import.name.as_str();
-
-    let (add_prefix, add_suffix) = match dll_import.import_name_type {
-        Some(PeImportNameType::NoPrefix) => (false, true),
-        Some(PeImportNameType::Undecorated) => (false, false),
-        _ => (true, true),
-    };
-
-    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
-    let mut decorated_name = String::with_capacity(name.len() + 6);
-
-    if disable_name_mangling {
-        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
-        decorated_name.push('\x01');
-    }
-
-    let prefix = if add_prefix && dll_import.is_fn {
-        match dll_import.calling_convention {
-            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
-            DllCallingConvention::Stdcall(_) => (!mingw
-                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
-            .then_some('_'),
-            DllCallingConvention::Fastcall(_) => Some('@'),
-        }
-    } else if !dll_import.is_fn && !mingw {
-        // For static variables, prefix with '_' on MSVC.
-        Some('_')
-    } else {
-        None
-    };
-    if let Some(prefix) = prefix {
-        decorated_name.push(prefix);
-    }
-
-    decorated_name.push_str(name);
-
-    if add_suffix && dll_import.is_fn {
-        match dll_import.calling_convention {
-            DllCallingConvention::C => {}
-            DllCallingConvention::Stdcall(arg_list_size)
-            | DllCallingConvention::Fastcall(arg_list_size) => {
-                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
-            }
-            DllCallingConvention::Vectorcall(arg_list_size) => {
-                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
-            }
-        }
-    }
-
-    decorated_name
-}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 80aa2018c81..75b298f14ca 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -1,13 +1,6 @@
-use crate::base;
-use crate::common::{self, CodegenCx};
-use crate::debuginfo;
-use crate::errors::{
-    InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined,
-};
-use crate::llvm::{self, True};
-use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
-use crate::value::Value;
+use std::ops::Range;
+
+use rustc_codegen_ssa::common;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -24,9 +17,18 @@ use rustc_session::config::Lto;
 use rustc_target::abi::{
     Align, AlignFromBytesError, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
 };
-use std::ops::Range;
 use tracing::{debug, instrument, trace};
 
+use crate::common::CodegenCx;
+use crate::errors::{
+    InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined,
+};
+use crate::llvm::{self, True};
+use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
+use crate::value::Value;
+use crate::{base, debuginfo};
+
 pub fn const_alloc_to_llvm<'ll>(
     cx: &CodegenCx<'ll, '_>,
     alloc: ConstAllocation<'_>,
@@ -194,7 +196,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             g2
         }
     } else if cx.tcx.sess.target.arch == "x86"
-        && let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
+        && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
     {
         cx.declare_global(
             &common::i686_decorated_name(
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 49677dcf12f..dd3f39ecead 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1,19 +1,13 @@
-use crate::attributes;
-use crate::back::write::to_llvm_code_model;
-use crate::callee::get_fn;
-use crate::coverageinfo;
-use crate::debuginfo;
-use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
-use crate::llvm;
-use crate::llvm_util;
-use crate::type_::Type;
-use crate::value::Value;
+use std::borrow::Borrow;
+use std::cell::{Cell, RefCell};
+use std::ffi::CStr;
+use std::str;
 
+use libc::c_uint;
 use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
 use rustc_codegen_ssa::errors as ssa_errors;
 use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::base_n::ToBaseN;
-use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
+use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
@@ -24,20 +18,23 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
-use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
+use rustc_session::config::{
+    BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, PAuthKey, PacRet,
+};
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx};
+use rustc_target::abi::call::FnAbi;
+use rustc_target::abi::{HasDataLayout, TargetDataLayout, VariantIdx};
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
 use smallvec::SmallVec;
 
-use libc::c_uint;
-use std::borrow::Borrow;
-use std::cell::{Cell, RefCell};
-use std::ffi::CStr;
-use std::str;
+use crate::back::write::to_llvm_code_model;
+use crate::callee::get_fn;
+use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
+use crate::type_::Type;
+use crate::value::Value;
+use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
 
 /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM
 /// `llvm::Context` so that several compilation units may be optimized in parallel.
@@ -152,7 +149,7 @@ pub unsafe fn create_module<'ll>(
 
     // Ensure the data-layout values hardcoded remain the defaults.
     {
-        let tm = crate::back::write::create_informational_target_machine(tcx.sess);
+        let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
         unsafe {
             llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
         }
@@ -778,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.debugtrap", fn() -> void);
         ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
 
-        ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16);
-        ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
-        ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
-        ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128);
+        ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16);
+        ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32);
+        ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64);
+        ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128);
 
         ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 14a94468587..9433385c23a 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -1,5 +1,3 @@
-use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
-
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_index::bit_set::BitSet;
@@ -11,6 +9,8 @@ use rustc_middle::ty::Instance;
 use rustc_span::Symbol;
 use tracing::{debug, instrument};
 
+use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
+
 /// Holds all of the coverage mapping data associated with a function instance,
 /// collected during traversal of `Coverage` statements in the function's MIR.
 #[derive(Debug)]
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index d2c0f20c285..f8929a26011 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,21 +1,19 @@
-use crate::common::CodegenCx;
-use crate::coverageinfo;
-use crate::coverageinfo::ffi::CounterMappingRegion;
-use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
-use crate::llvm;
-
 use itertools::Itertools as _;
 use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::IndexVec;
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, mir};
 use rustc_span::def_id::DefIdSet;
 use rustc_span::Symbol;
 use tracing::debug;
 
+use crate::common::CodegenCx;
+use crate::coverageinfo::ffi::CounterMappingRegion;
+use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
+use crate::{coverageinfo, llvm};
+
 /// Generates and exports the Coverage Map.
 ///
 /// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 7b7f8c885bb..20a713b8564 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,9 +1,4 @@
-use crate::llvm;
-
-use crate::builder::Builder;
-use crate::common::CodegenCx;
-use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
-use crate::coverageinfo::map_data::FunctionCoverageCollector;
+use std::cell::RefCell;
 
 use libc::c_uint;
 use rustc_codegen_ssa::traits::{
@@ -19,7 +14,11 @@ use rustc_middle::ty::Instance;
 use rustc_target::abi::{Align, Size};
 use tracing::{debug, instrument};
 
-use std::cell::RefCell;
+use crate::builder::Builder;
+use crate::common::CodegenCx;
+use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
+use crate::coverageinfo::map_data::FunctionCoverageCollector;
+use crate::llvm;
 
 pub(crate) mod ffi;
 pub(crate) mod map_data;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 6a63eda4b99..efe616838bf 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -1,18 +1,17 @@
-use super::metadata::file_metadata;
-use super::utils::DIB;
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
 use rustc_codegen_ssa::traits::*;
-
-use crate::common::CodegenCx;
-use crate::llvm;
-use crate::llvm::debuginfo::{DILocation, DIScope};
+use rustc_index::bit_set::BitSet;
+use rustc_index::Idx;
 use rustc_middle::mir::{Body, SourceScope};
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
 
-use rustc_index::bit_set::BitSet;
-use rustc_index::Idx;
+use super::metadata::file_metadata;
+use super::utils::DIB;
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::{DILocation, DIScope};
 
 /// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
 // FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index d82b1e1e721..5a08f2f00e5 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -1,18 +1,19 @@
 // .debug_gdb_scripts binary section.
 
-use crate::llvm;
-
-use crate::builder::Builder;
-use crate::common::CodegenCx;
-use crate::value::Value;
 use rustc_ast::attr;
 use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_middle::{bug, middle::debugger_visualizer::DebuggerVisualizerType};
+use rustc_middle::bug;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
 use rustc_session::config::{CrateType, DebugInfo};
 use rustc_span::symbol::sym;
 
+use crate::builder::Builder;
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::value::Value;
+
 /// Inserts a side-effect free instruction sequence that makes sure that the
 /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
 pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 364c35f3107..ad638588612 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1,32 +1,14 @@
-use self::type_map::DINodeCreationResult;
-use self::type_map::Stub;
-use self::type_map::UniqueTypeId;
-
-use super::namespace::mangled_name_of_instance;
-use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
-use super::utils::{
-    create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB,
-};
-use super::CodegenUnitDebugContext;
-
-use crate::abi;
-use crate::common::CodegenCx;
-use crate::debuginfo::metadata::type_map::build_type_with_children;
-use crate::debuginfo::utils::fat_pointer_kind;
-use crate::debuginfo::utils::FatPtrKind;
-use crate::llvm;
-use crate::llvm::debuginfo::{
-    DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
-    DebugNameTableKind,
-};
-use crate::value::Value;
+use std::borrow::Cow;
+use std::fmt::{self, Write};
+use std::hash::{Hash, Hasher};
+use std::path::{Path, PathBuf};
+use std::{iter, ptr};
 
-use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
-use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
+use libc::{c_char, c_longlong, c_uint};
+use rustc_codegen_ssa::debuginfo::type_names::{cpp_like_debuginfo, VTableNameKind};
 use rustc_codegen_ssa::traits::*;
 use rustc_fs_util::path_to_c_string;
-use rustc_hir::def::CtorKind;
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
@@ -36,21 +18,29 @@ use rustc_middle::ty::{
 };
 use rustc_session::config::{self, DebugInfo, Lto};
 use rustc_span::symbol::Symbol;
-use rustc_span::{hygiene, FileName, DUMMY_SP};
-use rustc_span::{FileNameDisplayPreference, SourceFile};
+use rustc_span::{hygiene, FileName, FileNameDisplayPreference, SourceFile, DUMMY_SP};
 use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::DebuginfoKind;
 use smallvec::smallvec;
 use tracing::{debug, instrument};
 
-use libc::{c_char, c_longlong, c_uint};
-use std::borrow::Cow;
-use std::fmt::{self, Write};
-use std::hash::{Hash, Hasher};
-use std::iter;
-use std::path::{Path, PathBuf};
-use std::ptr;
+use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId};
+use super::namespace::mangled_name_of_instance;
+use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
+use super::utils::{
+    create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB,
+};
+use super::CodegenUnitDebugContext;
+use crate::common::CodegenCx;
+use crate::debuginfo::metadata::type_map::build_type_with_children;
+use crate::debuginfo::utils::{fat_pointer_kind, FatPtrKind};
+use crate::llvm::debuginfo::{
+    DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
+    DebugNameTableKind,
+};
+use crate::value::Value;
+use crate::{abi, llvm};
 
 impl PartialEq for llvm::Metadata {
     fn eq(&self, other: &Self) -> bool {
@@ -874,7 +864,8 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
     codegen_unit_name: &str,
     debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
 ) -> &'ll DIDescriptor {
-    use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+    use rustc_session::config::RemapPathScopeComponents;
+    use rustc_session::RemapFileNameExt;
     let mut name_in_debuginfo = tcx
         .sess
         .local_crate_source_file()
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index cf7dddce84f..13006638bb3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -1,41 +1,27 @@
 use std::borrow::Cow;
 
 use libc::c_uint;
-use rustc_codegen_ssa::{
-    debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
-    traits::ConstMethods,
-};
-
+use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
+use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
+use rustc_codegen_ssa::traits::ConstMethods;
 use rustc_index::IndexVec;
-use rustc_middle::{
-    bug,
-    ty::{
-        self,
-        layout::{LayoutOf, TyAndLayout},
-        AdtDef, CoroutineArgs, CoroutineArgsExt, Ty,
-    },
-};
+use rustc_middle::bug;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
 use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
 use smallvec::smallvec;
 
-use crate::{
-    common::CodegenCx,
-    debuginfo::{
-        metadata::{
-            build_field_di_node,
-            enums::{tag_base_type, DiscrResult},
-            file_metadata, size_and_align_of, type_di_node,
-            type_map::{self, Stub, UniqueTypeId},
-            unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec,
-            NO_GENERICS, NO_SCOPE_METADATA, UNKNOWN_LINE_NUMBER,
-        },
-        utils::DIB,
-    },
-    llvm::{
-        self,
-        debuginfo::{DIFile, DIFlags, DIType},
-    },
+use crate::common::CodegenCx;
+use crate::debuginfo::metadata::enums::{tag_base_type, DiscrResult};
+use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
+use crate::debuginfo::metadata::{
+    build_field_di_node, file_metadata, size_and_align_of, type_di_node, unknown_file_metadata,
+    visibility_di_flags, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA,
+    UNKNOWN_LINE_NUMBER,
 };
+use crate::debuginfo::utils::DIB;
+use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
+use crate::llvm::{self};
 
 // The names of the associated constants in each variant wrapper struct.
 // These have to match up with the names being used in `intrinsic.natvis`.
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 96be1900ab2..fc3adaf0681 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -1,45 +1,29 @@
-use rustc_codegen_ssa::debuginfo::{
-    type_names::{compute_debuginfo_type_name, cpp_like_debuginfo},
-    wants_c_like_enum_debuginfo,
-};
+use std::borrow::Cow;
+
+use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
+use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
 use rustc_hir::def::CtorKind;
 use rustc_index::IndexSlice;
-use rustc_middle::{
-    bug,
-    mir::CoroutineLayout,
-    ty::{
-        self,
-        layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
-        AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef,
-    },
-};
+use rustc_middle::bug;
+use rustc_middle::mir::CoroutineLayout;
+use rustc_middle::ty::layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
 use rustc_span::Symbol;
 use rustc_target::abi::{
     FieldIdx, HasDataLayout, Integer, Primitive, TagEncoding, VariantIdx, Variants,
 };
-use std::borrow::Cow;
-
-use crate::{
-    common::CodegenCx,
-    debuginfo::{
-        metadata::{
-            build_field_di_node, build_generic_type_param_di_nodes, type_di_node,
-            type_map::{self, Stub},
-            unknown_file_metadata, UNKNOWN_LINE_NUMBER,
-        },
-        utils::{create_DIArray, get_namespace_for_item, DIB},
-    },
-    llvm::{
-        self,
-        debuginfo::{DIFlags, DIType},
-    },
-};
 
-use super::{
-    size_and_align_of,
-    type_map::{DINodeCreationResult, UniqueTypeId},
-    SmallVec,
+use super::type_map::{DINodeCreationResult, UniqueTypeId};
+use super::{size_and_align_of, SmallVec};
+use crate::common::CodegenCx;
+use crate::debuginfo::metadata::type_map::{self, Stub};
+use crate::debuginfo::metadata::{
+    build_field_di_node, build_generic_type_param_di_nodes, type_di_node, unknown_file_metadata,
+    UNKNOWN_LINE_NUMBER,
 };
+use crate::debuginfo::utils::{create_DIArray, get_namespace_for_item, DIB};
+use crate::llvm::debuginfo::{DIFlags, DIType};
+use crate::llvm::{self};
 
 mod cpp_like;
 mod native;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index 63a9ce2fdf9..d7e3b47e0bd 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -1,37 +1,26 @@
 use std::borrow::Cow;
 
-use crate::{
-    common::CodegenCx,
-    debuginfo::{
-        metadata::{
-            enums::tag_base_type,
-            file_metadata, size_and_align_of, type_di_node,
-            type_map::{self, Stub, StubInfo, UniqueTypeId},
-            unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec,
-            NO_GENERICS, UNKNOWN_LINE_NUMBER,
-        },
-        utils::{create_DIArray, get_namespace_for_item, DIB},
-    },
-    llvm::{
-        self,
-        debuginfo::{DIFile, DIFlags, DIType},
-    },
-};
 use libc::c_uint;
-use rustc_codegen_ssa::{
-    debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
-    traits::ConstMethods,
-};
-use rustc_middle::{
-    bug,
-    ty::{
-        self,
-        layout::{LayoutOf, TyAndLayout},
-    },
-};
+use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
+use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
+use rustc_codegen_ssa::traits::ConstMethods;
+use rustc_middle::bug;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self};
 use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
 use smallvec::smallvec;
 
+use crate::common::CodegenCx;
+use crate::debuginfo::metadata::enums::tag_base_type;
+use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
+use crate::debuginfo::metadata::{
+    file_metadata, size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
+    DINodeCreationResult, SmallVec, NO_GENERICS, UNKNOWN_LINE_NUMBER,
+};
+use crate::debuginfo::utils::{create_DIArray, get_namespace_for_item, DIB};
+use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
+use crate::llvm::{self};
+
 /// Build the debuginfo node for an enum type. The listing below shows how such a
 /// type looks like at the LLVM IR/DWARF level. It is a `DW_TAG_structure_type`
 /// with a single `DW_TAG_variant_part` that in turn contains a `DW_TAG_variant`
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 17931911f87..25b2df9c52c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -1,27 +1,18 @@
 use std::cell::RefCell;
 
-use rustc_data_structures::{
-    fingerprint::Fingerprint,
-    fx::FxHashMap,
-    stable_hasher::{HashStable, StableHasher},
-};
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
-use rustc_middle::{
-    bug,
-    ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt},
-};
+use rustc_middle::bug;
+use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_target::abi::{Align, Size, VariantIdx};
 
-use crate::{
-    common::CodegenCx,
-    debuginfo::utils::{create_DIArray, debug_context, DIB},
-    llvm::{
-        self,
-        debuginfo::{DIFlags, DIScope, DIType},
-    },
-};
-
 use super::{unknown_file_metadata, SmallVec, UNKNOWN_LINE_NUMBER};
+use crate::common::CodegenCx;
+use crate::debuginfo::utils::{create_DIArray, debug_context, DIB};
+use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
+use crate::llvm::{self};
 
 mod private {
     use rustc_macros::HashStable;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 3486ce4becb..b23e05182ca 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -1,33 +1,21 @@
 #![doc = include_str!("doc.md")]
 
-use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
-use rustc_data_structures::unord::UnordMap;
-
-use self::metadata::{file_metadata, type_di_node};
-use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
-use self::namespace::mangled_name_of_instance;
-use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
-
-use crate::abi::FnAbi;
-use crate::builder::Builder;
-use crate::common::CodegenCx;
-use crate::llvm;
-use crate::llvm::debuginfo::{
-    DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
-    DIVariable,
-};
-use crate::value::Value;
+use std::cell::{OnceCell, RefCell};
+use std::iter;
+use std::ops::Range;
 
+use libc::c_uint;
 use rustc_codegen_ssa::debuginfo::type_names;
+use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgsRef, Instance, ParamEnv, Ty, TypeVisitableExt};
 use rustc_session::config::{self, DebugInfo};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
@@ -35,15 +23,22 @@ use rustc_span::{
     BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId,
 };
 use rustc_target::abi::Size;
-
-use libc::c_uint;
 use smallvec::SmallVec;
-use std::cell::OnceCell;
-use std::cell::RefCell;
-use std::iter;
-use std::ops::Range;
 use tracing::debug;
 
+use self::metadata::{file_metadata, type_di_node, UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
+use self::namespace::mangled_name_of_instance;
+use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
+use crate::abi::FnAbi;
+use crate::builder::Builder;
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::{
+    DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
+    DIVariable,
+};
+use crate::value::Value;
+
 mod create_scope_map;
 pub mod gdb;
 pub mod metadata;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
index fa61c7dde18..5c4f8fe99e3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
@@ -1,13 +1,13 @@
 // Namespace Handling.
 
-use super::utils::{debug_context, DIB};
 use rustc_codegen_ssa::debuginfo::type_names;
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Instance};
 
+use super::utils::{debug_context, DIB};
 use crate::common::CodegenCx;
 use crate::llvm;
 use crate::llvm::debuginfo::DIScope;
-use rustc_hir::def_id::DefId;
 
 pub fn mangled_name_of_instance<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 9bd2ccceadf..e542aa96e8a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -1,13 +1,12 @@
 // Utility Functions.
 
-use super::namespace::item_namespace;
-use super::CodegenUnitDebugContext;
-
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty};
 use tracing::trace;
 
+use super::namespace::item_namespace;
+use super::CodegenUnitDebugContext;
 use crate::common::CodegenCx;
 use crate::llvm;
 use crate::llvm::debuginfo::{DIArray, DIBuilder, DIDescriptor, DIScope};
@@ -63,7 +62,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     pointee_ty: Ty<'tcx>,
 ) -> Option<FatPtrKind> {
-    let pointee_tail_ty = cx.tcx.struct_tail_erasing_lifetimes(pointee_ty, cx.param_env());
+    let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
     let layout = cx.layout_of(pointee_tail_ty);
     trace!(
         "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index bf86d0e0569..2aa349b2782 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -11,13 +11,6 @@
 //! * Use define_* family of methods when you might be defining the Value.
 //! * When in doubt, define.
 
-use crate::abi::{FnAbi, FnAbiLlvmExt};
-use crate::attributes;
-use crate::context::CodegenCx;
-use crate::llvm;
-use crate::llvm::AttributePlace::Function;
-use crate::type_::Type;
-use crate::value::Value;
 use itertools::Itertools;
 use rustc_codegen_ssa::traits::TypeMembershipMethods;
 use rustc_data_structures::fx::FxIndexSet;
@@ -26,6 +19,13 @@ use rustc_sanitizers::{cfi, kcfi};
 use smallvec::SmallVec;
 use tracing::debug;
 
+use crate::abi::{FnAbi, FnAbiLlvmExt};
+use crate::context::CodegenCx;
+use crate::llvm::AttributePlace::Function;
+use crate::type_::Type;
+use crate::value::Value;
+use crate::{attributes, llvm};
+
 /// Declare a function.
 ///
 /// If there’s a value with the same name already declared, the function will
@@ -137,7 +137,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             llvm::Visibility::Default,
             fn_abi.llvm_type(self),
         );
-        fn_abi.apply_attrs_llfn(self, llfn);
+        fn_abi.apply_attrs_llfn(self, llfn, instance);
 
         if self.tcx.sess.is_sanitizer_cfi_enabled() {
             if let Some(instance) = instance {
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 40ac2f9c8ba..7e53d32ce8c 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -1,13 +1,13 @@
-use std::borrow::Cow;
 use std::ffi::CString;
 use std::path::Path;
 
-use crate::fluent_generated as fluent;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
 
+use crate::fluent_generated as fluent;
+
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
 #[note]
@@ -71,28 +71,6 @@ pub(crate) struct InvalidMinimumAlignmentTooLarge {
 pub(crate) struct SanitizerMemtagRequiresMte;
 
 #[derive(Diagnostic)]
-#[diag(codegen_llvm_error_writing_def_file)]
-pub(crate) struct ErrorWritingDEFFile {
-    pub error: std::io::Error,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_error_calling_dlltool)]
-pub(crate) struct ErrorCallingDllTool<'a> {
-    pub dlltool_path: Cow<'a, str>,
-    pub error: std::io::Error,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_dlltool_fail_import_library)]
-pub(crate) struct DlltoolFailImportLibrary<'a> {
-    pub dlltool_path: Cow<'a, str>,
-    pub dlltool_args: String,
-    pub stdout: Cow<'a, str>,
-    pub stderr: Cow<'a, str>,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_llvm_dynamic_linking_with_lto)]
 #[note]
 pub(crate) struct DynamicLinkingWithLTO;
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 68c3d47e826..f5558723d11 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1,17 +1,11 @@
-use crate::abi::{Abi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode};
-use crate::builder::Builder;
-use crate::context::CodegenCx;
-use crate::llvm;
-use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
-use crate::va_arg::emit_va_arg;
-use crate::value::Value;
+use std::assert_matches::assert_matches;
+use std::cmp::Ordering;
 
 use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
-use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_hir as hir;
 use rustc_middle::mir::BinOp;
@@ -23,7 +17,14 @@ use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size};
 use rustc_target::spec::{HasTargetSpec, PanicStrategy};
 use tracing::debug;
 
-use std::cmp::Ordering;
+use crate::abi::{Abi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode};
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::llvm;
+use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
+use crate::va_arg::emit_va_arg;
+use crate::value::Value;
 
 fn get_simple_intrinsic<'ll>(
     cx: &CodegenCx<'ll, '_>,
@@ -35,10 +36,10 @@ fn get_simple_intrinsic<'ll>(
         sym::sqrtf64 => "llvm.sqrt.f64",
         sym::sqrtf128 => "llvm.sqrt.f128",
 
-        sym::powif16 => "llvm.powi.f16",
-        sym::powif32 => "llvm.powi.f32",
-        sym::powif64 => "llvm.powi.f64",
-        sym::powif128 => "llvm.powi.f128",
+        sym::powif16 => "llvm.powi.f16.i32",
+        sym::powif32 => "llvm.powi.f32.i32",
+        sym::powif64 => "llvm.powi.f64.i32",
+        sym::powif128 => "llvm.powi.f128.i32",
 
         sym::sinf16 => "llvm.sin.f16",
         sym::sinf32 => "llvm.sin.f32",
@@ -203,6 +204,35 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             }
             sym::unlikely => self
                 .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
+            sym::select_unpredictable => {
+                let cond = args[0].immediate();
+                assert_eq!(args[1].layout, args[2].layout);
+                let select = |bx: &mut Self, true_val, false_val| {
+                    let result = bx.select(cond, true_val, false_val);
+                    bx.set_unpredictable(&result);
+                    result
+                };
+                match (args[1].val, args[2].val) {
+                    (OperandValue::Ref(true_val), OperandValue::Ref(false_val)) => {
+                        assert!(true_val.llextra.is_none());
+                        assert!(false_val.llextra.is_none());
+                        assert_eq!(true_val.align, false_val.align);
+                        let ptr = select(self, true_val.llval, false_val.llval);
+                        let selected =
+                            OperandValue::Ref(PlaceValue::new_sized(ptr, true_val.align));
+                        selected.store(self, result);
+                        return Ok(());
+                    }
+                    (OperandValue::Immediate(_), OperandValue::Immediate(_))
+                    | (OperandValue::Pair(_, _), OperandValue::Pair(_, _)) => {
+                        let true_val = args[1].immediate_or_packed_pair(self);
+                        let false_val = args[2].immediate_or_packed_pair(self);
+                        select(self, true_val, false_val)
+                    }
+                    (OperandValue::ZeroSized, OperandValue::ZeroSized) => return Ok(()),
+                    _ => span_bug!(span, "Incompatible OperandValue for select_unpredictable"),
+                }
+            }
             sym::catch_unwind => {
                 catch_unwind_intrinsic(
                     self,
@@ -1113,7 +1143,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     if cfg!(debug_assertions) {
         for (ty, arg) in arg_tys.iter().zip(args) {
             if ty.is_simd() {
-                assert!(matches!(arg.val, OperandValue::Immediate(_)));
+                assert_matches!(arg.val, OperandValue::Immediate(_));
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index a96993b9aba..43164390a1c 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -8,6 +8,7 @@
 #![allow(internal_features)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(exact_size_is_empty)]
 #![feature(extern_types)]
 #![feature(hash_raw_entry)]
@@ -17,9 +18,13 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
+use std::any::Any;
+use std::ffi::CStr;
+use std::io::Write;
+use std::mem::ManuallyDrop;
+
 use back::owned_target_machine::OwnedTargetMachine;
 use back::write::{create_informational_target_machine, create_target_machine};
-
 use errors::ParseTargetMachineConfig;
 pub use llvm_util::target_features;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -28,8 +33,7 @@ use rustc_codegen_ssa::back::write::{
     CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
 };
 use rustc_codegen_ssa::traits::*;
-use rustc_codegen_ssa::ModuleCodegen;
-use rustc_codegen_ssa::{CodegenResults, CompiledModule};
+use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
 use rustc_metadata::EncodedMetadata;
@@ -40,11 +44,6 @@ use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
-use std::any::Any;
-use std::ffi::CStr;
-use std::io::Write;
-use std::mem::ManuallyDrop;
-
 mod back {
     pub mod archive;
     pub mod lto;
@@ -271,7 +270,7 @@ impl CodegenBackend for LlvmCodegenBackend {
 
     fn provide(&self, providers: &mut Providers) {
         providers.global_backend_features =
-            |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
+            |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true, false)
     }
 
     fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
@@ -394,9 +393,10 @@ impl CodegenBackend for LlvmCodegenBackend {
         codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorGuaranteed> {
-        use crate::back::archive::LlvmArchiveBuilderBuilder;
         use rustc_codegen_ssa::back::link::link_binary;
 
+        use crate::back::archive::LlvmArchiveBuilderBuilder;
+
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
         link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs)
@@ -435,7 +435,7 @@ impl ModuleLlvm {
             ModuleLlvm {
                 llmod_raw,
                 llcx,
-                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
+                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs
index 7d948970223..4dabde55e98 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs
@@ -1,9 +1,9 @@
 //! A wrapper around LLVM's archive (.a) code
 
-use rustc_fs_util::path_to_c_string;
 use std::path::Path;
-use std::slice;
-use std::str;
+use std::{slice, str};
+
+use rustc_fs_util::path_to_c_string;
 
 pub struct ArchiveRO {
     pub raw: &'static mut super::Archive,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
index 73e1b08a3d7..a4cb5a25d1b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
@@ -1,13 +1,12 @@
 //! LLVM diagnostic reports.
 
-pub use self::Diagnostic::*;
-pub use self::OptimizationDiagnosticKind::*;
-
-use crate::value::Value;
 use libc::c_uint;
+use rustc_span::InnerSpan;
 
+pub use self::Diagnostic::*;
+pub use self::OptimizationDiagnosticKind::*;
 use super::{DiagnosticInfo, SMDiagnostic};
-use rustc_span::InnerSpan;
+use crate::value::Value;
 
 #[derive(Copy, Clone, Debug)]
 pub enum OptimizationDiagnosticKind {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 3beda28ac1f..faabbcb020d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1,18 +1,16 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
+use std::marker::PhantomData;
+
+use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
+
 use super::debuginfo::{
     DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
     DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DILocation, DINameSpace,
     DISPFlags, DIScope, DISubprogram, DISubrange, DITemplateTypeParameter, DIType, DIVariable,
     DebugEmissionKind, DebugNameTableKind,
 };
-
-use libc::{c_char, c_int, c_uint, size_t};
-use libc::{c_ulonglong, c_void};
-
-use std::marker::PhantomData;
-
 use super::RustString;
 
 pub type Bool = c_uint;
@@ -428,6 +426,7 @@ pub enum MetadataType {
     MD_nontemporal = 9,
     MD_mem_parallel_loop_access = 10,
     MD_nonnull = 11,
+    MD_unpredictable = 15,
     MD_align = 17,
     MD_type = 19,
     MD_vcall_visibility = 28,
@@ -697,9 +696,10 @@ pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void
 pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
 
 pub mod debuginfo {
-    use super::{InvariantOpaque, Metadata};
     use bitflags::bitflags;
 
+    use super::{InvariantOpaque, Metadata};
+
     #[repr(C)]
     pub struct DIBuilder<'a>(InvariantOpaque<'a>);
 
@@ -1575,6 +1575,12 @@ extern "C" {
     pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute;
     pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute;
     pub fn LLVMRustCreateMemoryEffectsAttr(C: &Context, effects: MemoryEffects) -> &Attribute;
+    pub fn LLVMRustCreateRangeAttribute(
+        C: &Context,
+        num_bits: c_uint,
+        lower_words: *const u64,
+        upper_words: *const u64,
+    ) -> &Attribute;
 
     // Operations on functions
     pub fn LLVMRustGetOrInsertFunction<'a>(
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 6ab1eea9597..d0db350a149 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -1,5 +1,15 @@
 #![allow(non_snake_case)]
 
+use std::cell::RefCell;
+use std::ffi::{CStr, CString};
+use std::str::FromStr;
+use std::string::FromUtf8Error;
+
+use libc::c_uint;
+use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_llvm::RustString;
+use rustc_target::abi::{Align, Size, WrappingRange};
+
 pub use self::AtomicRmwBinOp::*;
 pub use self::CallConv::*;
 pub use self::CodeGenOptSize::*;
@@ -8,15 +18,6 @@ pub use self::Linkage::*;
 pub use self::MetadataType::*;
 pub use self::RealPredicate::*;
 
-use libc::c_uint;
-use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_llvm::RustString;
-use rustc_target::abi::Align;
-use std::cell::RefCell;
-use std::ffi::{CStr, CString};
-use std::str::FromStr;
-use std::string::FromUtf8Error;
-
 pub mod archive_ro;
 pub mod diagnostic;
 mod ffi;
@@ -104,6 +105,21 @@ pub fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribu
     unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
 }
 
+pub fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
+    let lower = range.start;
+    let upper = range.end.wrapping_add(1);
+    let lower_words = [lower as u64, (lower >> 64) as u64];
+    let upper_words = [upper as u64, (upper >> 64) as u64];
+    unsafe {
+        LLVMRustCreateRangeAttribute(
+            llcx,
+            size.bits().try_into().unwrap(),
+            lower_words.as_ptr(),
+            upper_words.as_ptr(),
+        )
+    }
+}
+
 #[derive(Copy, Clone)]
 pub enum AttributePlace {
     ReturnValue,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 4d56d1d3b1a..9fd8ca43789 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,13 +1,14 @@
-use crate::back::write::create_informational_target_machine;
-use crate::errors::{
-    FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
-    UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
-};
-use crate::llvm;
+use std::ffi::{c_char, c_void, CStr, CString};
+use std::fmt::Write;
+use std::path::Path;
+use std::sync::Once;
+use std::{ptr, slice, str};
+
 use libc::c_int;
 use rustc_codegen_ssa::base::wants_wasm_eh;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::unord::UnordSet;
 use rustc_fs_util::path_to_c_string;
 use rustc_middle::bug;
 use rustc_session::config::{PrintKind, PrintRequest};
@@ -16,13 +17,12 @@ use rustc_span::symbol::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
 
-use std::ffi::{c_char, c_void, CStr, CString};
-use std::fmt::Write;
-use std::path::Path;
-use std::ptr;
-use std::slice;
-use std::str;
-use std::sync::Once;
+use crate::back::write::create_informational_target_machine;
+use crate::errors::{
+    FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
+    UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
+};
+use crate::llvm;
 
 static INIT: Once = Once::new();
 
@@ -240,40 +240,8 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
         }
         // In LLVM neon implicitly enables fp, but we manually enable
         // neon when a feature only implicitly enables fp
-        ("aarch64", "f32mm") => {
-            LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "f64mm") => {
-            LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "fhm") => {
-            LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "fp16") => {
-            LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "jsconv") => {
-            LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve") => {
-            LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2") => {
-            LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-aes") => {
-            LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-sm4") => {
-            LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-sha3") => {
-            LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency(
-            "sve2-bitperm",
-            TargetFeatureFoldStrength::EnableOnly("neon"),
-        ),
+        ("aarch64", "fhm") => LLVMFeature::new("fp16fml"),
+        ("aarch64", "fp16") => LLVMFeature::new("fullfp16"),
         // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
         // `fast-unaligned-access`. In LLVM 19, it was split back out.
         ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
@@ -309,11 +277,53 @@ pub fn check_tied_features(
 /// Used to generate cfg variables and apply features
 /// Must express features in the way Rust understands them
 pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
-    let target_machine = create_informational_target_machine(sess);
+    let mut features = vec![];
+
+    // Add base features for the target
+    let target_machine = create_informational_target_machine(sess, true);
+    features.extend(
+        sess.target
+            .supported_target_features()
+            .iter()
+            .filter(|(feature, _, _)| {
+                // skip checking special features, as LLVM may not understands them
+                if RUSTC_SPECIAL_FEATURES.contains(feature) {
+                    return true;
+                }
+                // check that all features in a given smallvec are enabled
+                for llvm_feature in to_llvm_features(sess, feature) {
+                    let cstr = SmallCStr::new(llvm_feature);
+                    if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
+                        return false;
+                    }
+                }
+                true
+            })
+            .map(|(feature, _, _)| Symbol::intern(feature)),
+    );
+
+    // Add enabled features
+    for (enabled, feature) in
+        sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
+            Some('+') => Some((true, Symbol::intern(&s[1..]))),
+            Some('-') => Some((false, Symbol::intern(&s[1..]))),
+            _ => None,
+        })
+    {
+        if enabled {
+            features.extend(sess.target.implied_target_features(std::iter::once(feature)));
+        } else {
+            features.retain(|f| {
+                !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
+            });
+        }
+    }
+
+    // Filter enabled features based on feature gates
     sess.target
         .supported_target_features()
         .iter()
-        .filter_map(|&(feature, gate)| {
+        .filter_map(|&(feature, gate, _)| {
             if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
                 Some(feature)
             } else {
@@ -321,18 +331,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
             }
         })
         .filter(|feature| {
-            // skip checking special features, as LLVM may not understands them
-            if RUSTC_SPECIAL_FEATURES.contains(feature) {
-                return true;
-            }
-            // check that all features in a given smallvec are enabled
-            for llvm_feature in to_llvm_features(sess, feature) {
-                let cstr = SmallCStr::new(llvm_feature);
-                if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
-                    return false;
-                }
-            }
-            true
+            RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature))
         })
         .map(|feature| Symbol::intern(feature))
         .collect()
@@ -387,7 +386,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
         .target
         .supported_target_features()
         .iter()
-        .map(|(feature, _gate)| {
+        .map(|(feature, _gate, _implied)| {
             // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
             let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
             let desc =
@@ -441,7 +440,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
 
 pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
     require_inited();
-    let tm = create_informational_target_machine(sess);
+    let tm = create_informational_target_machine(sess, false);
     match req.kind {
         PrintKind::TargetCPUs => {
             // SAFETY generate a C compatible string from a byte slice to pass
@@ -489,7 +488,11 @@ pub fn target_cpu(sess: &Session) -> &str {
 
 /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
 /// `--target` and similar).
-pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<String> {
+pub(crate) fn global_llvm_features(
+    sess: &Session,
+    diagnostics: bool,
+    only_base_features: bool,
+) -> Vec<String> {
     // Features that come earlier are overridden by conflicting features later in the string.
     // Typically we'll want more explicit settings to override the implicit ones, so:
     //
@@ -549,94 +552,124 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
     }
 
     // -Ctarget-features
-    let supported_features = sess.target.supported_target_features();
-    let (llvm_major, _, _) = get_version();
-    let mut featsmap = FxHashMap::default();
-    let feats = sess
-        .opts
-        .cg
-        .target_feature
-        .split(',')
-        .filter_map(|s| {
-            let enable_disable = match s.chars().next() {
-                None => return None,
-                Some(c @ ('+' | '-')) => c,
-                Some(_) => {
-                    if diagnostics {
-                        sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
+    if !only_base_features {
+        let supported_features = sess.target.supported_target_features();
+        let (llvm_major, _, _) = get_version();
+        let mut featsmap = FxHashMap::default();
+
+        // insert implied features
+        let mut all_rust_features = vec![];
+        for feature in sess.opts.cg.target_feature.split(',') {
+            match feature.strip_prefix('+') {
+                Some(feature) => all_rust_features.extend(
+                    UnordSet::from(
+                        sess.target
+                            .implied_target_features(std::iter::once(Symbol::intern(feature))),
+                    )
+                    .to_sorted_stable_ord()
+                    .iter()
+                    .map(|s| format!("+{}", s.as_str())),
+                ),
+                _ => all_rust_features.push(feature.to_string()),
+            }
+        }
+
+        let feats = all_rust_features
+            .iter()
+            .filter_map(|s| {
+                let enable_disable = match s.chars().next() {
+                    None => return None,
+                    Some(c @ ('+' | '-')) => c,
+                    Some(_) => {
+                        if diagnostics {
+                            sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
+                        }
+                        return None;
                     }
-                    return None;
-                }
-            };
+                };
 
-            let feature = backend_feature_name(sess, s)?;
-            // Warn against use of LLVM specific feature names and unstable features on the CLI.
-            if diagnostics {
-                let feature_state = supported_features.iter().find(|&&(v, _)| v == feature);
-                if feature_state.is_none() {
-                    let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
-                        let llvm_features = to_llvm_features(sess, rust_feature);
-                        if llvm_features.contains(feature) && !llvm_features.contains(rust_feature)
-                        {
-                            Some(rust_feature)
+                let feature = backend_feature_name(sess, s)?;
+                // Warn against use of LLVM specific feature names and unstable features on the CLI.
+                if diagnostics {
+                    let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
+                    if feature_state.is_none() {
+                        let rust_feature =
+                            supported_features.iter().find_map(|&(rust_feature, _, _)| {
+                                let llvm_features = to_llvm_features(sess, rust_feature);
+                                if llvm_features.contains(feature)
+                                    && !llvm_features.contains(rust_feature)
+                                {
+                                    Some(rust_feature)
+                                } else {
+                                    None
+                                }
+                            });
+                        let unknown_feature = if let Some(rust_feature) = rust_feature {
+                            UnknownCTargetFeature {
+                                feature,
+                                rust_feature: PossibleFeature::Some { rust_feature },
+                            }
                         } else {
-                            None
-                        }
-                    });
-                    let unknown_feature = if let Some(rust_feature) = rust_feature {
-                        UnknownCTargetFeature {
-                            feature,
-                            rust_feature: PossibleFeature::Some { rust_feature },
-                        }
-                    } else {
-                        UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
-                    };
-                    sess.dcx().emit_warn(unknown_feature);
-                } else if feature_state
-                    .is_some_and(|(_name, feature_gate)| !feature_gate.is_stable())
-                {
-                    // An unstable feature. Warn about using it.
-                    sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+                            UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                        };
+                        sess.dcx().emit_warn(unknown_feature);
+                    } else if feature_state
+                        .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
+                    {
+                        // An unstable feature. Warn about using it.
+                        sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+                    }
                 }
-            }
 
-            if diagnostics {
-                // FIXME(nagisa): figure out how to not allocate a full hashset here.
-                featsmap.insert(feature, enable_disable == '+');
-            }
+                if diagnostics {
+                    // FIXME(nagisa): figure out how to not allocate a full hashset here.
+                    featsmap.insert(feature, enable_disable == '+');
+                }
 
-            // rustc-specific features do not get passed down to LLVM…
-            if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-                return None;
-            }
+                // rustc-specific features do not get passed down to LLVM…
+                if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+                    return None;
+                }
 
-            // if the target-feature is "backchain" and LLVM version is greater than 18
-            // then we also need to add "+backchain" to the target-features attribute.
-            // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
-            if feature == "backchain" && llvm_major < 18 {
-                return None;
-            }
-            // ... otherwise though we run through `to_llvm_features` when
-            // passing requests down to LLVM. This means that all in-language
-            // features also work on the command line instead of having two
-            // different names when the LLVM name and the Rust name differ.
-            let llvm_feature = to_llvm_features(sess, feature);
-
-            Some(
-                std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
-                    .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
-                        match (enable_disable, feat) {
+                // if the target-feature is "backchain" and LLVM version is greater than 18
+                // then we also need to add "+backchain" to the target-features attribute.
+                // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
+                if feature == "backchain" && llvm_major < 18 {
+                    return None;
+                }
+                // ... otherwise though we run through `to_llvm_features` when
+                // passing requests down to LLVM. This means that all in-language
+                // features also work on the command line instead of having two
+                // different names when the LLVM name and the Rust name differ.
+                let llvm_feature = to_llvm_features(sess, feature);
+
+                Some(
+                    std::iter::once(format!(
+                        "{}{}",
+                        enable_disable, llvm_feature.llvm_feature_name
+                    ))
+                    .chain(llvm_feature.dependency.into_iter().filter_map(
+                        move |feat| match (enable_disable, feat) {
                             ('-' | '+', TargetFeatureFoldStrength::Both(f))
                             | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
                                 Some(format!("{enable_disable}{f}"))
                             }
                             _ => None,
-                        }
-                    })),
-            )
-        })
-        .flatten();
-    features.extend(feats);
+                        },
+                    )),
+                )
+            })
+            .flatten();
+        features.extend(feats);
+
+        if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
+            sess.dcx().emit_err(TargetFeatureDisableOrEnable {
+                features: f,
+                span: None,
+                missing_features: None,
+            });
+        }
+    }
 
     // -Zfixed-x18
     if sess.opts.unstable_opts.fixed_x18 {
@@ -647,14 +680,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         }
     }
 
-    if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-        sess.dcx().emit_err(TargetFeatureDisableOrEnable {
-            features: f,
-            span: None,
-            missing_features: None,
-        });
-    }
-
     features
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 282a186be99..f1ef359594b 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -1,9 +1,3 @@
-use crate::attributes;
-use crate::base;
-use crate::context::CodegenCx;
-use crate::errors::SymbolAlreadyDefined;
-use crate::llvm;
-use crate::type_of::LayoutLlvmExt;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -15,6 +9,11 @@ use rustc_session::config::CrateType;
 use rustc_target::spec::RelocModel;
 use tracing::debug;
 
+use crate::context::CodegenCx;
+use crate::errors::SymbolAlreadyDefined;
+use crate::type_of::LayoutLlvmExt;
+use crate::{base, llvm};
+
 impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
     fn predefine_static(
         &self,
@@ -88,8 +87,6 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
 
         debug!("predefine_fn: instance = {:?}", instance);
 
-        attributes::from_fn_attrs(self, lldecl, instance);
-
         unsafe {
             if self.should_assume_dso_local(lldecl, false) {
                 llvm::LLVMRustSetDSOLocal(lldecl, true);
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index f1141c57ced..7e3ab19898d 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -1,12 +1,6 @@
-pub use crate::llvm::Type;
+use std::{fmt, ptr};
 
-use crate::abi::{FnAbiLlvmExt, LlvmType};
-use crate::common;
-use crate::context::CodegenCx;
-use crate::llvm;
-use crate::llvm::{Bool, False, True};
-use crate::type_of::LayoutLlvmExt;
-use crate::value::Value;
+use libc::{c_char, c_uint};
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::small_c_str::SmallCStr;
@@ -16,10 +10,13 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
 use rustc_target::abi::{AddressSpace, Align, Integer, Size};
 
-use std::fmt;
-use std::ptr;
-
-use libc::{c_char, c_uint};
+use crate::abi::{FnAbiLlvmExt, LlvmType};
+use crate::context::CodegenCx;
+pub use crate::llvm::Type;
+use crate::llvm::{Bool, False, True};
+use crate::type_of::LayoutLlvmExt;
+use crate::value::Value;
+use crate::{common, llvm};
 
 impl PartialEq for Type {
     fn eq(&self, other: &Self) -> bool {
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 7be941ed749..4755fa08afb 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -1,16 +1,15 @@
-use crate::common::*;
-use crate::type_::Type;
+use std::fmt::Write;
+
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
-use rustc_target::abi::{Abi, Align, FieldsShape};
-use rustc_target::abi::{Float, Int, Pointer};
-use rustc_target::abi::{Scalar, Size, Variants};
+use rustc_target::abi::{Abi, Align, FieldsShape, Float, Int, Pointer, Scalar, Size, Variants};
 use tracing::debug;
 
-use std::fmt::Write;
+use crate::common::*;
+use crate::type_::Type;
 
 fn uncached_llvm_type<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 220bb77d3fd..94e77c5bd70 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -1,16 +1,15 @@
-use crate::builder::Builder;
-use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
-use crate::value::Value;
+use rustc_codegen_ssa::common::IntPredicate;
 use rustc_codegen_ssa::mir::operand::OperandRef;
-use rustc_codegen_ssa::{
-    common::IntPredicate,
-    traits::{BaseTypeMethods, BuilderMethods, ConstMethods},
-};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods, ConstMethods};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::Ty;
 use rustc_target::abi::{Align, Endian, HasDataLayout, Size};
 
+use crate::builder::Builder;
+use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
+use crate::value::Value;
+
 fn round_pointer_up_to_alignment<'ll>(
     bx: &mut Builder<'_, 'll, '_>,
     addr: &'ll Value,
diff --git a/compiler/rustc_codegen_llvm/src/value.rs b/compiler/rustc_codegen_llvm/src/value.rs
index 1338a229566..6295b0de356 100644
--- a/compiler/rustc_codegen_llvm/src/value.rs
+++ b/compiler/rustc_codegen_llvm/src/value.rs
@@ -1,10 +1,8 @@
-pub use crate::llvm::Value;
+use std::hash::{Hash, Hasher};
+use std::{fmt, ptr};
 
 use crate::llvm;
-
-use std::fmt;
-use std::hash::{Hash, Hasher};
-use std::ptr;
+pub use crate::llvm::Value;
 
 impl PartialEq for Value {
     fn eq(&self, other: &Self) -> bool {
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index f7b5b0f310b..6e1c323cbd0 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-ar_archive_writer = "0.3.0"
+ar_archive_writer = "0.3.3"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
 cc = "1.0.90"
@@ -41,7 +41,7 @@ tempfile = "3.2"
 thin-vec = "0.2.12"
 thorin-dwp = "0.7"
 tracing = "0.1"
-wasm-encoder = "0.200.0"
+wasm-encoder = "0.210.0"
 # tidy-alphabetical-end
 
 [target.'cfg(unix)'.dependencies]
@@ -50,7 +50,7 @@ libc = "0.2.50"
 # tidy-alphabetical-end
 
 [dependencies.object]
-version = "0.32.1"
+version = "0.36.2"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"]
 
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 000fe2e3ce0..80f25d42a08 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -4,8 +4,7 @@ codegen_ssa_add_native_library = failed to add native library {$library_path}: {
 
 codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
 
-codegen_ssa_archive_build_failure =
-    failed to build archive: {$error}
+codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error}
 
 codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
 
@@ -25,8 +24,19 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
 
 codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
 
+codegen_ssa_dlltool_fail_import_library =
+    Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
+    {$stdout}
+    {$stderr}
+
+codegen_ssa_error_calling_dlltool =
+    Error calling dlltool '{$dlltool_path}': {$error}
+
 codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
 
+codegen_ssa_error_writing_def_file =
+    Error writing .DEF file: {$error}
+
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
@@ -198,7 +208,7 @@ codegen_ssa_read_file = failed to read file: {$message}
 
 codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
 
-codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error}
+codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib at `{$path}`: {$error}
 
 codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
 
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 6e7d736eb29..11bcd727501 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -23,10 +23,11 @@
 //! allows for doing a more fine-grained check to see if pre- or post-lto data
 //! was re-used.
 
-use crate::errors;
+use std::borrow::Cow;
+use std::fmt;
+
 use rustc_ast as ast;
-use rustc_data_structures::unord::UnordMap;
-use rustc_data_structures::unord::UnordSet;
+use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::mir::mono::CodegenUnitNameBuilder;
@@ -34,11 +35,11 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
-use std::borrow::Cow;
-use std::fmt;
 use thin_vec::ThinVec;
 use tracing::debug;
 
+use crate::errors;
+
 #[allow(missing_docs)]
 pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTracker)) {
     tcx.dep_graph.with_ignore(|| {
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index ae649cd77c4..ce55d99f506 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -1,24 +1,24 @@
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::memmap::Mmap;
-use rustc_session::cstore::DllImport;
-use rustc_session::Session;
-use rustc_span::symbol::Symbol;
-
-use super::metadata::search_for_section;
+use std::env;
+use std::error::Error;
+use std::ffi::OsString;
+use std::fs::{self, File};
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
 
 use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember};
 pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER};
 use object::read::archive::ArchiveFile;
 use object::read::macho::FatArch;
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::memmap::Mmap;
+use rustc_session::Session;
+use rustc_span::symbol::Symbol;
 use tempfile::Builder as TempFileBuilder;
 
-use std::error::Error;
-use std::fs::{self, File};
-use std::io::{self, Write};
-use std::path::{Path, PathBuf};
-
+use super::metadata::search_for_section;
 // Re-exporting for rustc_codegen_llvm::back::archive
 pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
+use crate::errors::{DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorWritingDEFFile};
 
 pub trait ArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
@@ -32,10 +32,9 @@ pub trait ArchiveBuilderBuilder {
         &self,
         sess: &Session,
         lib_name: &str,
-        dll_imports: &[DllImport],
-        tmpdir: &Path,
-        is_direct_dependency: bool,
-    ) -> PathBuf;
+        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        output_path: &Path,
+    );
 
     fn extract_bundled_libs<'a>(
         &'a self,
@@ -74,6 +73,130 @@ pub trait ArchiveBuilderBuilder {
     }
 }
 
+pub fn create_mingw_dll_import_lib(
+    sess: &Session,
+    lib_name: &str,
+    import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+    output_path: &Path,
+) {
+    let def_file_path = output_path.with_extension("def");
+
+    let def_file_content = format!(
+        "EXPORTS\n{}",
+        import_name_and_ordinal_vector
+            .into_iter()
+            .map(|(name, ordinal)| {
+                match ordinal {
+                    Some(n) => format!("{name} @{n} NONAME"),
+                    None => name,
+                }
+            })
+            .collect::<Vec<String>>()
+            .join("\n")
+    );
+
+    match std::fs::write(&def_file_path, def_file_content) {
+        Ok(_) => {}
+        Err(e) => {
+            sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
+        }
+    };
+
+    // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
+    // able to control the *exact* spelling of each of the symbols that are being imported:
+    // hence we don't want `dlltool` adding leading underscores automatically.
+    let dlltool = find_binutils_dlltool(sess);
+    let temp_prefix = {
+        let mut path = PathBuf::from(&output_path);
+        path.pop();
+        path.push(lib_name);
+        path
+    };
+    // dlltool target architecture args from:
+    // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
+    let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
+        "x86_64" => ("i386:x86-64", "--64"),
+        "x86" => ("i386", "--32"),
+        "aarch64" => ("arm64", "--64"),
+        "arm" => ("arm", "--32"),
+        _ => panic!("unsupported arch {}", sess.target.arch),
+    };
+    let mut dlltool_cmd = std::process::Command::new(&dlltool);
+    dlltool_cmd
+        .arg("-d")
+        .arg(def_file_path)
+        .arg("-D")
+        .arg(lib_name)
+        .arg("-l")
+        .arg(&output_path)
+        .arg("-m")
+        .arg(dlltool_target_arch)
+        .arg("-f")
+        .arg(dlltool_target_bitness)
+        .arg("--no-leading-underscore")
+        .arg("--temp-prefix")
+        .arg(temp_prefix);
+
+    match dlltool_cmd.output() {
+        Err(e) => {
+            sess.dcx().emit_fatal(ErrorCallingDllTool {
+                dlltool_path: dlltool.to_string_lossy(),
+                error: e,
+            });
+        }
+        // dlltool returns '0' on failure, so check for error output instead.
+        Ok(output) if !output.stderr.is_empty() => {
+            sess.dcx().emit_fatal(DlltoolFailImportLibrary {
+                dlltool_path: dlltool.to_string_lossy(),
+                dlltool_args: dlltool_cmd
+                    .get_args()
+                    .map(|arg| arg.to_string_lossy())
+                    .collect::<Vec<_>>()
+                    .join(" "),
+                stdout: String::from_utf8_lossy(&output.stdout),
+                stderr: String::from_utf8_lossy(&output.stderr),
+            })
+        }
+        _ => {}
+    }
+}
+
+fn find_binutils_dlltool(sess: &Session) -> OsString {
+    assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
+    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
+        return dlltool_path.clone().into_os_string();
+    }
+
+    let tool_name: OsString = if sess.host.options.is_like_windows {
+        // If we're compiling on Windows, always use "dlltool.exe".
+        "dlltool.exe"
+    } else {
+        // On other platforms, use the architecture-specific name.
+        match sess.target.arch.as_ref() {
+            "x86_64" => "x86_64-w64-mingw32-dlltool",
+            "x86" => "i686-w64-mingw32-dlltool",
+            "aarch64" => "aarch64-w64-mingw32-dlltool",
+
+            // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
+            _ => "dlltool",
+        }
+    }
+    .into();
+
+    // NOTE: it's not clear how useful it is to explicitly search PATH.
+    for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
+        let full_path = dir.join(&tool_name);
+        if full_path.is_file() {
+            return full_path.into_os_string();
+        }
+    }
+
+    // The user didn't specify the location of the dlltool binary, and we weren't able
+    // to find the appropriate one on the PATH. Just return the name of the tool
+    // and let the invocation fail with a hopefully useful error message.
+    tool_name
+}
+
 pub trait ArchiveBuilder {
     fn add_file(&mut self, path: &Path);
 
@@ -110,13 +233,11 @@ impl<'a> ArArchiveBuilder<'a> {
 }
 
 fn try_filter_fat_archs(
-    archs: object::read::Result<&[impl FatArch]>,
+    archs: &[impl FatArch],
     target_arch: object::Architecture,
     archive_path: &Path,
     archive_map_data: &[u8],
 ) -> io::Result<Option<PathBuf>> {
-    let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
-
     let desired = match archs.iter().find(|a| a.architecture() == target_arch) {
         Some(a) => a,
         None => return Ok(None),
@@ -146,17 +267,15 @@ pub fn try_extract_macho_fat_archive(
         _ => return Ok(None),
     };
 
-    match object::macho::FatHeader::parse(&*archive_map) {
-        Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
-            let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
-            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
-        }
-        Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
-            let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
-            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
-        }
+    if let Ok(h) = object::read::macho::MachOFatFile32::parse(&*archive_map) {
+        let archs = h.arches();
+        try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+    } else if let Ok(h) = object::read::macho::MachOFatFile64::parse(&*archive_map) {
+        let archs = h.arches();
+        try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+    } else {
         // Not a FatHeader at all, just return None.
-        _ => Ok(None),
+        Ok(None)
     }
 }
 
@@ -213,7 +332,9 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
         let sess = self.sess;
         match self.build_inner(output) {
             Ok(any_members) => any_members,
-            Err(e) => sess.dcx().emit_fatal(ArchiveBuildFailure { error: e }),
+            Err(error) => {
+                sess.dcx().emit_fatal(ArchiveBuildFailure { path: output.to_owned(), error })
+            }
         }
     }
 }
@@ -224,11 +345,7 @@ impl<'a> ArArchiveBuilder<'a> {
             "gnu" => ArchiveKind::Gnu,
             "bsd" => ArchiveKind::Bsd,
             "darwin" => ArchiveKind::Darwin,
-            "coff" => {
-                // FIXME: ar_archive_writer doesn't support COFF archives yet.
-                // https://github.com/rust-lang/ar_archive_writer/issues/9
-                ArchiveKind::Gnu
-            }
+            "coff" => ArchiveKind::Coff,
             "aix_big" => ArchiveKind::AixBig,
             kind => {
                 self.sess.dcx().emit_fatal(UnknownArchiveKind { kind });
diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs
index 3a89be89951..95c4af2e59e 100644
--- a/compiler/rustc_codegen_ssa/src/back/command.rs
+++ b/compiler/rustc_codegen_ssa/src/back/command.rs
@@ -2,10 +2,8 @@
 //! read the arguments that are built up.
 
 use std::ffi::{OsStr, OsString};
-use std::fmt;
-use std::io;
-use std::mem;
 use std::process::{self, Output};
+use std::{fmt, io, mem};
 
 use rustc_target::spec::LldFlavor;
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8c582fac0d8..7bad9d33e7d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1,3 +1,15 @@
+use std::collections::BTreeSet;
+use std::ffi::OsString;
+use std::fs::{read, File, OpenOptions};
+use std::io::{BufWriter, Write};
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
+use std::process::{ExitStatus, Output, Stdio};
+use std::{env, fmt, fs, io, mem, str};
+
+use cc::windows_registry;
+use itertools::Itertools;
+use regex::Regex;
 use rustc_arena::TypedArena;
 use rustc_ast::CRATE_NODE_ID;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -12,9 +24,10 @@ use rustc_middle::bug;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::LinkerFeaturesCli;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, OutFileName, Strip};
-use rustc_session::config::{OutputFilenames, OutputType, PrintKind, SplitDwarfKind};
+use rustc_session::config::{
+    self, CFGuard, CrateType, DebugInfo, LinkerFeaturesCli, OutFileName, OutputFilenames,
+    OutputType, PrintKind, SplitDwarfKind, Strip,
+};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
@@ -24,11 +37,13 @@ use rustc_session::utils::NativeLibKind;
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::crt_objects::CrtObjects;
-use rustc_target::spec::LinkSelfContainedDefault;
-use rustc_target::spec::LinkerFlavorCli;
-use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
-use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures};
-use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
+use rustc_target::spec::{
+    Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
+    LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
+    SplitDebuginfo,
+};
+use tempfile::Builder as TempFileBuilder;
+use tracing::{debug, info, warn};
 
 use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
 use super::command::Command;
@@ -36,24 +51,10 @@ use super::linker::{self, Linker};
 use super::metadata::{create_wrapper_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
 use crate::{
-    errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+    common, errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo,
+    NativeLib,
 };
 
-use cc::windows_registry;
-use regex::Regex;
-use tempfile::Builder as TempFileBuilder;
-
-use itertools::Itertools;
-use std::collections::BTreeSet;
-use std::ffi::OsString;
-use std::fs::{read, File, OpenOptions};
-use std::io::{BufWriter, Write};
-use std::ops::Deref;
-use std::path::{Path, PathBuf};
-use std::process::{ExitStatus, Output, Stdio};
-use std::{env, fmt, fs, io, mem, str};
-use tracing::{debug, info, warn};
-
 pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
         if e.kind() != io::ErrorKind::NotFound {
@@ -390,17 +391,13 @@ fn link_rlib<'a>(
         }
     }
 
-    for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
-    {
-        let output_path = archive_builder_builder.create_dll_import_lib(
-            sess,
-            &raw_dylib_name,
-            &raw_dylib_imports,
-            tmpdir.as_ref(),
-            true,
-        );
-
+    for output_path in create_dll_import_libs(
+        sess,
+        archive_builder_builder,
+        codegen_results.crate_info.used_libraries.iter(),
+        tmpdir.as_ref(),
+        true,
+    )? {
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
             sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
@@ -488,6 +485,47 @@ fn collate_raw_dylibs<'a>(
         .collect())
 }
 
+fn create_dll_import_libs<'a>(
+    sess: &Session,
+    archive_builder_builder: &dyn ArchiveBuilderBuilder,
+    used_libraries: impl IntoIterator<Item = &'a NativeLib>,
+    tmpdir: &Path,
+    is_direct_dependency: bool,
+) -> Result<Vec<PathBuf>, ErrorGuaranteed> {
+    Ok(collate_raw_dylibs(sess, used_libraries)?
+        .into_iter()
+        .map(|(raw_dylib_name, raw_dylib_imports)| {
+            let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
+            let output_path = tmpdir.join(format!("{raw_dylib_name}{name_suffix}.lib"));
+
+            let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target);
+
+            let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports
+                .iter()
+                .map(|import: &DllImport| {
+                    if sess.target.arch == "x86" {
+                        (
+                            common::i686_decorated_name(import, mingw_gnu_toolchain, false),
+                            import.ordinal(),
+                        )
+                    } else {
+                        (import.name.to_string(), import.ordinal())
+                    }
+                })
+                .collect();
+
+            archive_builder_builder.create_dll_import_lib(
+                sess,
+                &raw_dylib_name,
+                import_name_and_ordinal_vector,
+                &output_path,
+            );
+
+            output_path
+        })
+        .collect())
+}
+
 /// Create a static archive.
 ///
 /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -700,7 +738,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
                 .truncate(true)
                 .open(dwp_out_filename)?,
         );
-        let mut output_stream = object::write::StreamingBuffer::new(output_stream);
+        let mut output_stream = thorin::object::write::StreamingBuffer::new(output_stream);
         package.finish()?.emit(&mut output_stream)?;
         output_stream.result()?;
         output_stream.into_inner().flush()?;
@@ -2065,17 +2103,61 @@ fn add_local_crate_metadata_objects(
 }
 
 /// Add sysroot and other globally set directories to the directory search list.
-fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
-    // The default library location, we need this to find the runtime.
-    // The location of crates will be determined as needed.
-    let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
-    cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+fn add_library_search_dirs(
+    cmd: &mut dyn Linker,
+    sess: &Session,
+    self_contained_components: LinkSelfContainedComponents,
+    apple_sdk_root: Option<&Path>,
+) {
+    if !sess.opts.unstable_opts.link_native_libraries {
+        return;
+    }
 
-    // Special directory with libraries used only in self-contained linkage mode
-    if self_contained {
-        let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path();
+    // Library search paths explicitly supplied by user (`-L` on the command line).
+    for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir));
+    }
+    for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
+        // Contrary to the `-L` docs only framework-specific paths are considered here.
+        if search_path.kind != PathKind::All {
+            cmd.framework_path(&search_path.dir);
+        }
+    }
+
+    // The toolchain ships some native library components and self-contained linking was enabled.
+    // Add the self-contained library directory to search paths.
+    if self_contained_components.intersects(
+        LinkSelfContainedComponents::LIBC
+            | LinkSelfContainedComponents::UNWIND
+            | LinkSelfContainedComponents::MINGW,
+    ) {
+        let lib_path = sess.target_filesearch(PathKind::Native).get_self_contained_lib_path();
         cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
     }
+
+    // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
+    // library directory instead of the self-contained directories.
+    // Sanitizer libraries have the same issue and are also linked by name on Apple targets.
+    // The targets here should be in sync with `copy_third_party_objects` in bootstrap.
+    // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
+    // and sanitizers to self-contained directory, and stop adding this search path.
+    if sess.target.vendor == "fortanix"
+        || sess.target.os == "linux"
+        || sess.target.os == "fuchsia"
+        || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
+    {
+        let lib_path = sess.target_filesearch(PathKind::Native).get_lib_path();
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+    }
+
+    // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
+    // we must have the support library stubs in the library search path (#121430).
+    if let Some(sdk_root) = apple_sdk_root
+        && sess.target.llvm_target.contains("macabi")
+    {
+        cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
+        cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
+    }
 }
 
 /// Add options making relocation sections in the produced ELF files read-only
@@ -2261,16 +2343,14 @@ fn linker_with_args(
     );
 
     // Link with the import library generated for any raw-dylib functions.
-    for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
-    {
-        cmd.add_object(&archive_builder_builder.create_dll_import_lib(
-            sess,
-            &raw_dylib_name,
-            &raw_dylib_imports,
-            tmpdir,
-            true,
-        ));
+    for output_path in create_dll_import_libs(
+        sess,
+        archive_builder_builder,
+        codegen_results.crate_info.used_libraries.iter(),
+        tmpdir,
+        true,
+    )? {
+        cmd.add_object(&output_path);
     }
     // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
     // they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2295,16 +2375,14 @@ fn linker_with_args(
         .flatten()
         .collect::<Vec<_>>();
     native_libraries_from_nonstatics.sort_unstable_by(|a, b| a.name.as_str().cmp(b.name.as_str()));
-    for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
-    {
-        cmd.add_object(&archive_builder_builder.create_dll_import_lib(
-            sess,
-            &raw_dylib_name,
-            &raw_dylib_imports,
-            tmpdir,
-            false,
-        ));
+    for output_path in create_dll_import_libs(
+        sess,
+        archive_builder_builder,
+        native_libraries_from_nonstatics,
+        tmpdir,
+        false,
+    )? {
+        cmd.add_object(&output_path);
     }
 
     // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
@@ -2367,7 +2445,7 @@ fn add_order_independent_options(
     // Take care of the flavors and CLI options requesting the `lld` linker.
     add_lld_args(cmd, sess, flavor, self_contained_components);
 
-    add_apple_sdk(cmd, sess, flavor);
+    let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
 
     add_link_script(cmd, sess, tmpdir, crate_type);
 
@@ -2423,7 +2501,7 @@ fn add_order_independent_options(
 
     cmd.linker_plugin_lto();
 
-    add_library_search_dirs(cmd, sess, self_contained_components.are_any_components_enabled());
+    add_library_search_dirs(cmd, sess, self_contained_components, apple_sdk_root.as_deref());
 
     cmd.output_filename(out_filename);
 
@@ -2568,16 +2646,7 @@ fn add_native_libs_from_crate(
             NativeLibKind::Static { bundle, whole_archive } => {
                 if link_static {
                     let bundle = bundle.unwrap_or(true);
-                    let whole_archive = whole_archive == Some(true)
-                        // Backward compatibility case: this can be a rlib (so `+whole-archive`
-                        // cannot be added explicitly if necessary, see the error in `fn link_rlib`)
-                        // compiled as an executable due to `--test`. Use whole-archive implicitly,
-                        // like before the introduction of native lib modifiers.
-                        || (whole_archive == None
-                            && bundle
-                            && cnum == LOCAL_CRATE
-                            && sess.is_test_crate());
-
+                    let whole_archive = whole_archive == Some(true);
                     if bundle && cnum != LOCAL_CRATE {
                         if let Some(filename) = lib.filename {
                             // If rlib contains native libs as archives, they are unpacked to tmpdir.
@@ -2637,19 +2706,6 @@ fn add_local_native_libraries(
     tmpdir: &Path,
     link_output_kind: LinkOutputKind,
 ) {
-    if sess.opts.unstable_opts.link_native_libraries {
-        // User-supplied library search paths (-L on the command line). These are the same paths
-        // used to find Rust crates, so some of them may have been added already by the previous
-        // crate linking code. This only allows them to be found at compile time so it is still
-        // entirely up to outside forces to make sure that library can be found at runtime.
-        for search_path in sess.target_filesearch(PathKind::All).search_paths() {
-            match search_path.kind {
-                PathKind::Framework => cmd.framework_path(&search_path.dir),
-                _ => cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)),
-            }
-        }
-    }
-
     // All static and dynamic native library dependencies are linked to the local crate.
     let link_static = true;
     let link_dynamic = true;
@@ -2911,7 +2967,8 @@ fn add_static_crate(
                 false
             }),
         ) {
-            sess.dcx().emit_fatal(errors::RlibArchiveBuildFailure { error });
+            sess.dcx()
+                .emit_fatal(errors::RlibArchiveBuildFailure { path: cratepath.clone(), error });
         }
         if archive.build(&dst) {
             link_upstream(&dst);
@@ -2943,7 +3000,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool
     }
 }
 
-fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
+fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option<PathBuf> {
     let arch = &sess.target.arch;
     let os = &sess.target.os;
     let llvm_target = &sess.target.llvm_target;
@@ -2951,11 +3008,11 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos")
         || !matches!(flavor, LinkerFlavor::Darwin(..))
     {
-        return;
+        return None;
     }
 
     if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
-        return;
+        return None;
     }
 
     let sdk_name = match (arch.as_ref(), os.as_ref()) {
@@ -2979,14 +3036,14 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         (_, "macos") => "macosx",
         _ => {
             sess.dcx().emit_err(errors::UnsupportedArch { arch, os });
-            return;
+            return None;
         }
     };
     let sdk_root = match get_apple_sdk_root(sdk_name) {
         Ok(s) => s,
         Err(e) => {
             sess.dcx().emit_err(e);
-            return;
+            return None;
         }
     };
 
@@ -3006,16 +3063,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         _ => unreachable!(),
     }
 
-    if llvm_target.contains("macabi") {
-        // Mac Catalyst uses the macOS SDK, but to link to iOS-specific
-        // frameworks, we must have the support library stubs in the library
-        // search path.
-
-        // The flags are called `-L` and `-F` both in Clang, ld64 and ldd.
-        let sdk_root = Path::new(&sdk_root);
-        cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
-        cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
-    }
+    Some(sdk_root.into())
 }
 
 fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootError<'_>> {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index dd134ebbe6b..febeb7093a3 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,8 +1,3 @@
-use super::command::Command;
-use super::symbol_export;
-use crate::errors;
-use rustc_span::symbol::sym;
-
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
 use std::io::prelude::*;
@@ -10,6 +5,7 @@ use std::io::{self, BufWriter};
 use std::path::{Path, PathBuf};
 use std::{env, iter, mem, str};
 
+use cc::windows_registry;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
 use rustc_middle::bug;
@@ -19,11 +15,14 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
-
-use cc::windows_registry;
 use tracing::{debug, warn};
 
+use super::command::Command;
+use super::symbol_export;
+use crate::errors;
+
 /// Disables non-English messages from localized linkers.
 /// Such messages may cause issues with text encoding on Windows (#35785)
 /// and prevent inspection of linker output in case of errors, which we occasionally do.
diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs
index 5291cad148e..8b6f6b5a220 100644
--- a/compiler/rustc_codegen_ssa/src/back/lto.rs
+++ b/compiler/rustc_codegen_ssa/src/back/lto.rs
@@ -1,12 +1,12 @@
-use super::write::CodegenContext;
-use crate::traits::*;
-use crate::ModuleCodegen;
+use std::ffi::CString;
+use std::sync::Arc;
 
 use rustc_data_structures::memmap::Mmap;
 use rustc_errors::FatalError;
 
-use std::ffi::CString;
-use std::sync::Arc;
+use super::write::CodegenContext;
+use crate::traits::*;
+use crate::ModuleCodegen;
 
 pub struct ThinModule<B: WriteBackendMethods> {
     pub shared: Arc<ThinShared<B>>,
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 264a98844ad..9b5a797ad51 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -10,7 +10,6 @@ use object::{
     elf, pe, xcoff, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
     ObjectSymbol, SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope,
 };
-
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
 use rustc_metadata::creader::MetadataLoader;
@@ -209,6 +208,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
         "powerpc64" => (Architecture::PowerPc64, None),
         "riscv32" => (Architecture::Riscv32, None),
         "riscv64" => (Architecture::Riscv64, None),
+        "sparc" => (Architecture::Sparc32Plus, None),
         "sparc64" => (Architecture::Sparc64, None),
         "avr" => (Architecture::Avr, None),
         "msp430" => (Architecture::Msp430, None),
@@ -656,7 +656,13 @@ pub fn create_metadata_file_for_wasm(sess: &Session, data: &[u8], section_name:
         imports.import(
             "env",
             "__linear_memory",
-            wasm_encoder::MemoryType { minimum: 0, maximum: None, memory64: true, shared: false },
+            wasm_encoder::MemoryType {
+                minimum: 0,
+                maximum: None,
+                memory64: true,
+                shared: false,
+                page_size_log2: None,
+            },
         );
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 82070d4453b..42f8c3114ff 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -1,8 +1,9 @@
+use std::ffi::OsString;
+use std::path::{Path, PathBuf};
+
 use pathdiff::diff_paths;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_fs_util::try_canonicalize;
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
 use tracing::debug;
 
 pub struct RPathConfig<'a> {
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
index c620e92db1f..0de0b8a52b1 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
@@ -1,8 +1,8 @@
-use super::RPathConfig;
-use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
 use std::ffi::OsString;
 use std::path::{Path, PathBuf};
 
+use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags, RPathConfig};
+
 #[test]
 fn test_rpaths_to_flags() {
     let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index b7ad09b055a..d2f11d48140 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -1,5 +1,3 @@
-use crate::base::allocator_kind_for_codegen;
-
 use std::collections::hash_map::Entry::*;
 
 use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE};
@@ -12,14 +10,14 @@ use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
 };
 use rustc_middle::query::LocalCrate;
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, SymbolName, TyCtxt};
-use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_session::config::{CrateType, OomStrategy};
 use rustc_target::spec::{SanitizerSet, TlsModel};
 use tracing::debug;
 
+use crate::base::allocator_kind_for_codegen;
+
 pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
     crates_export_threshold(tcx.crate_types())
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 56e94529bc1..70b45a852ca 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1,12 +1,11 @@
-use super::link::{self, ensure_removed};
-use super::lto::{self, SerializedModule};
-use super::symbol_export::symbol_name_for_instance_in_crate;
+use std::any::Any;
+use std::assert_matches::assert_matches;
+use std::marker::PhantomData;
+use std::path::{Path, PathBuf};
+use std::sync::mpsc::{channel, Receiver, Sender};
+use std::sync::Arc;
+use std::{fs, io, mem, str, thread};
 
-use crate::errors;
-use crate::traits::*;
-use crate::{
-    CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
-};
 use jobserver::{Acquired, Client};
 use rustc_ast::attr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -30,26 +29,25 @@ use rustc_middle::bug;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::exported_symbols::SymbolExportInfo;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType};
-use rustc_session::config::{Passes, SwitchWithOptPath};
+use rustc_session::config::{
+    self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath,
+};
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
 use rustc_target::spec::{MergeFunctions, SanitizerSet};
+use tracing::debug;
 
+use super::link::{self, ensure_removed};
+use super::lto::{self, SerializedModule};
+use super::symbol_export::symbol_name_for_instance_in_crate;
 use crate::errors::ErrorCreatingRemarkDir;
-use std::any::Any;
-use std::fs;
-use std::io;
-use std::marker::PhantomData;
-use std::mem;
-use std::path::{Path, PathBuf};
-use std::str;
-use std::sync::mpsc::{channel, Receiver, Sender};
-use std::sync::Arc;
-use std::thread;
-use tracing::debug;
+use crate::traits::*;
+use crate::{
+    errors, CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen,
+    ModuleKind,
+};
 
 const PRE_LTO_BC_EXT: &str = "pre-lto.bc";
 
@@ -1966,7 +1964,7 @@ impl SharedEmitterMain {
                     sess.dcx().abort_if_errors();
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
-                    assert!(matches!(level, Level::Error | Level::Warning | Level::Note));
+                    assert_matches!(level, Level::Error | Level::Warning | Level::Note);
                     let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
                     let mut err = Diag::<()>::new(sess.dcx(), level, msg);
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 399ac485850..f1e7f87f567 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -1,19 +1,8 @@
-use crate::assert_module_sources::CguReuse;
-use crate::back::link::are_upstream_rust_objects_already_included;
-use crate::back::metadata::create_compressed_metadata_file;
-use crate::back::write::{
-    compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
-    submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
-};
-use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
-use crate::errors;
-use crate::meth;
-use crate::mir;
-use crate::mir::operand::OperandValue;
-use crate::mir::place::PlaceRef;
-use crate::traits::*;
-use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind};
+use std::cmp;
+use std::collections::BTreeSet;
+use std::time::{Duration, Instant};
 
+use itertools::Itertools;
 use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS};
 use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
@@ -26,9 +15,8 @@ use rustc_metadata::EncodedMetadata;
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
-use rustc_middle::middle::exported_symbols;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_middle::middle::lang_items;
+use rustc_middle::middle::{exported_symbols, lang_items};
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::mir::BinOp;
 use rustc_middle::query::Providers;
@@ -39,14 +27,23 @@ use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Symbol, DUMMY_SP};
 use rustc_target::abi::FIRST_VARIANT;
-
-use std::cmp;
-use std::collections::BTreeSet;
-use std::time::{Duration, Instant};
-
-use itertools::Itertools;
 use tracing::{debug, info};
 
+use crate::assert_module_sources::CguReuse;
+use crate::back::link::are_upstream_rust_objects_already_included;
+use crate::back::metadata::create_compressed_metadata_file;
+use crate::back::write::{
+    compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
+    submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
+};
+use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
+use crate::mir::operand::OperandValue;
+use crate::mir::place::PlaceRef;
+use crate::traits::*;
+use crate::{
+    errors, meth, mir, CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
+};
+
 pub fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
     match op {
         BinOp::Eq => IntPredicate::IntEQ,
@@ -146,7 +143,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ) -> Bx::Value {
     let cx = bx.cx();
     let (source, target) =
-        cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
+        cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.param_env());
     match (source.kind(), target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => {
             cx.const_usize(len.eval_target_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index bfa4c683d56..4ab20c154cc 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -1,17 +1,20 @@
 use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
 use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
-use rustc_errors::{codes::*, struct_span_code_err, DiagMessage, SubdiagMessage};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
-use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
+use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
+use rustc_hir::{lang_items, LangItem};
 use rustc_middle::middle::codegen_fn_attrs::{
     CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
 };
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self as ty, TyCtxt};
-use rustc_session::{lint, parse::feature_err};
+use rustc_session::lint;
+use rustc_session::parse::feature_err;
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span};
 use rustc_target::spec::{abi, SanitizerSet};
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index ea2fd482e1f..bfb1d217eae 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -1,15 +1,16 @@
 #![allow(non_camel_case_types)]
 
 use rustc_hir::LangItem;
-use rustc_middle::mir;
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, layout::TyAndLayout, TyCtxt};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::{self, Instance, TyCtxt};
+use rustc_middle::{bug, mir, span_bug};
+use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
 use rustc_span::Span;
+use rustc_target::spec::Target;
 
 use crate::traits::*;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum IntPredicate {
     IntEQ,
     IntNE,
@@ -23,7 +24,7 @@ pub enum IntPredicate {
     IntSLE,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum RealPredicate {
     RealPredicateFalse,
     RealOEQ,
@@ -43,7 +44,7 @@ pub enum RealPredicate {
     RealPredicateTrue,
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum AtomicRmwBinOp {
     AtomicXchg,
     AtomicAdd,
@@ -58,7 +59,7 @@ pub enum AtomicRmwBinOp {
     AtomicUMin,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum AtomicOrdering {
     Unordered,
     Relaxed,
@@ -68,7 +69,7 @@ pub enum AtomicOrdering {
     SequentiallyConsistent,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum SynchronizationScope {
     SingleThread,
     CrossThread,
@@ -106,9 +107,10 @@ pub enum TypeKind {
 //            for now we content ourselves with providing a no-op HashStable
 //            implementation for CGUs.
 mod temp_stable_hash_impls {
-    use crate::ModuleCodegen;
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
+    use crate::ModuleCodegen;
+
     impl<HCX, M> HashStable<HCX> for ModuleCodegen<M> {
         fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
             // do nothing
@@ -176,3 +178,66 @@ pub fn asm_const_to_str<'tcx>(
         _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty),
     }
 }
+
+pub fn is_mingw_gnu_toolchain(target: &Target) -> bool {
+    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
+}
+
+pub fn i686_decorated_name(
+    dll_import: &DllImport,
+    mingw: bool,
+    disable_name_mangling: bool,
+) -> String {
+    let name = dll_import.name.as_str();
+
+    let (add_prefix, add_suffix) = match dll_import.import_name_type {
+        Some(PeImportNameType::NoPrefix) => (false, true),
+        Some(PeImportNameType::Undecorated) => (false, false),
+        _ => (true, true),
+    };
+
+    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
+    let mut decorated_name = String::with_capacity(name.len() + 6);
+
+    if disable_name_mangling {
+        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
+        decorated_name.push('\x01');
+    }
+
+    let prefix = if add_prefix && dll_import.is_fn {
+        match dll_import.calling_convention {
+            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
+            DllCallingConvention::Stdcall(_) => (!mingw
+                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
+            .then_some('_'),
+            DllCallingConvention::Fastcall(_) => Some('@'),
+        }
+    } else if !dll_import.is_fn && !mingw {
+        // For static variables, prefix with '_' on MSVC.
+        Some('_')
+    } else {
+        None
+    };
+    if let Some(prefix) = prefix {
+        decorated_name.push(prefix);
+    }
+
+    decorated_name.push_str(name);
+
+    if add_suffix && dll_import.is_fn {
+        use std::fmt::Write;
+
+        match dll_import.calling_convention {
+            DllCallingConvention::C => {}
+            DllCallingConvention::Stdcall(arg_list_size)
+            | DllCallingConvention::Fastcall(arg_list_size) => {
+                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
+            }
+            DllCallingConvention::Vectorcall(arg_list_size) => {
+                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
+            }
+        }
+    }
+
+    decorated_name
+}
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
index 60e9b40e8fb..1eaf593a6d7 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
@@ -1,4 +1,5 @@
-use rustc_middle::ty::{self, layout::TyAndLayout};
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::{self};
 use rustc_target::abi::Size;
 
 // FIXME(eddyb) find a place for this (or a way to replace it).
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 6a6d47fcbba..27558038927 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -11,6 +11,8 @@
 //   within the brackets).
 // * `"` is treated as the start of a string.
 
+use std::fmt::Write;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
@@ -18,14 +20,13 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
 use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
-use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{
+    self, ExistentialProjection, GenericArgKind, GenericArgsRef, ParamEnv, Ty, TyCtxt,
+};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::Integer;
 use smallvec::SmallVec;
 
-use std::fmt::Write;
-
 use crate::debuginfo::wants_c_like_enum_debuginfo;
 
 /// Compute the name of the type as it should be stored in debuginfo. Does not do
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index e9d31db9254..94bf0ab34e2 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,20 +1,23 @@
 //! Errors emitted by codegen_ssa
 
-use crate::assert_module_sources::CguReuse;
-use crate::back::command::Command;
-use crate::fluent_generated as fluent;
+use std::borrow::Cow;
+use std::io::Error;
+use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
+
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
+    Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
 };
 use rustc_macros::Diagnostic;
 use rustc_middle::ty::layout::LayoutError;
 use rustc_middle::ty::Ty;
 use rustc_span::{Span, Symbol};
 use rustc_type_ir::FloatTy;
-use std::borrow::Cow;
-use std::io::Error;
-use std::path::{Path, PathBuf};
-use std::process::ExitStatus;
+
+use crate::assert_module_sources::CguReuse;
+use crate::back::command::Command;
+use crate::fluent_generated as fluent;
 
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_incorrect_cgu_reuse_type)]
@@ -497,6 +500,7 @@ pub struct UnableToWriteDebuggerVisualizer {
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_rlib_archive_build_failure)]
 pub struct RlibArchiveBuildFailure {
+    pub path: PathBuf,
     pub error: Error,
 }
 
@@ -554,6 +558,7 @@ pub struct UnsupportedLinkSelfContained;
 #[diag(codegen_ssa_archive_build_failure)]
 // Public for rustc_codegen_llvm::back::archive
 pub struct ArchiveBuildFailure {
+    pub path: PathBuf,
     pub error: std::io::Error,
 }
 
@@ -1022,6 +1027,28 @@ pub struct FailedToGetLayout<'tcx> {
 }
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_dlltool_fail_import_library)]
+pub(crate) struct DlltoolFailImportLibrary<'a> {
+    pub dlltool_path: Cow<'a, str>,
+    pub dlltool_args: String,
+    pub stdout: Cow<'a, str>,
+    pub stderr: Cow<'a, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_error_writing_def_file)]
+pub(crate) struct ErrorWritingDEFFile {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_error_calling_dlltool)]
+pub(crate) struct ErrorCallingDllTool<'a> {
+    pub dlltool_path: Cow<'a, str>,
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_error_creating_remark_dir)]
 pub struct ErrorCreatingRemarkDir {
     pub error: std::io::Error,
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e801af40014..cb6d9d6f66e 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -4,6 +4,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
@@ -17,9 +18,12 @@
 //! The backend-agnostic functions of this crate use functions defined in various traits that
 //! have to be implemented by each backend.
 
+use std::collections::BTreeSet;
+use std::io;
+use std::path::{Path, PathBuf};
+
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def_id::CrateNum;
@@ -36,9 +40,6 @@ use rustc_session::cstore::{self, CrateSource};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
-use std::collections::BTreeSet;
-use std::io;
-use std::path::{Path, PathBuf};
 
 pub mod assert_module_sources;
 pub mod back;
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index febc8ee2be2..c9602d9cdae 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -1,5 +1,3 @@
-use crate::traits::*;
-
 use rustc_middle::bug;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::config::Lto;
@@ -7,6 +5,8 @@ use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::abi::call::FnAbi;
 use tracing::{debug, instrument};
 
+use crate::traits::*;
+
 #[derive(Copy, Clone, Debug)]
 pub struct VirtualIndex(u64);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index ac2b6ca4e95..6794365c9be 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -1,18 +1,18 @@
 //! An analysis to determine which locals require allocas and
 //! which do not.
 
-use super::FunctionCx;
-use crate::traits::*;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
-use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind};
+use rustc_middle::mir::{self, traversal, DefLocation, Location, TerminatorKind};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::{bug, span_bug};
 use tracing::debug;
 
+use super::FunctionCx;
+use crate::traits::*;
+
 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fx: &FunctionCx<'a, 'tcx, Bx>,
 ) -> BitSet<mir::Local> {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 9cb8b719b12..772adf13ff1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1,14 +1,4 @@
-use super::operand::OperandRef;
-use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized};
-use super::place::{PlaceRef, PlaceValue};
-use super::{CachedLlbb, FunctionCx, LocalRef};
-
-use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
-use crate::common::{self, IntPredicate};
-use crate::errors::CompilerBuiltinsCannotCall;
-use crate::meth;
-use crate::traits::*;
-use crate::MemFlags;
+use std::cmp;
 
 use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -19,13 +9,22 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::OptLevel;
-use rustc_span::{source_map::Spanned, sym, Span};
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, Span};
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
 use rustc_target::abi::{self, HasDataLayout, WrappingRange};
 use rustc_target::spec::abi::Abi;
 use tracing::{debug, info};
 
-use std::cmp;
+use super::operand::OperandRef;
+use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized};
+use super::place::{PlaceRef, PlaceValue};
+use super::{CachedLlbb, FunctionCx, LocalRef};
+use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
+use crate::common::{self, IntPredicate};
+use crate::errors::CompilerBuiltinsCannotCall;
+use crate::traits::*;
+use crate::{meth, MemFlags};
 
 // Indicates if we are in the middle of merging a BB's successor into it. This
 // can happen when BB jumps directly to its successor and the successor has no
@@ -924,8 +923,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // third argument must be constant. This is
                         // checked by the type-checker.
                         if i == 2 && intrinsic.name == sym::simd_shuffle {
+                            // FIXME: the simd_shuffle argument is actually an array,
+                            // not a vector, so we need this special hack to make sure
+                            // it is passed as an immediate. We should pass the
+                            // shuffle indices as a vector instead to avoid this hack.
                             if let mir::Operand::Constant(constant) = &arg.node {
-                                let (llval, ty) = self.simd_shuffle_indices(bx, constant);
+                                let (llval, ty) = self.immediate_const_vector(bx, constant);
                                 return OperandRef {
                                     val: Immediate(llval),
                                     layout: bx.layout_of(ty),
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 35e9a3b7dc2..0aa85b82038 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -1,14 +1,13 @@
-use crate::errors;
-use crate::mir::operand::OperandRef;
-use crate::traits::*;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_middle::ty::{self, Ty};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::ty::{self, Ty, ValTree};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_target::abi::Abi;
 
 use super::FunctionCx;
+use crate::errors;
+use crate::mir::operand::OperandRef;
+use crate::traits::*;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn eval_mir_constant_to_operand(
@@ -29,7 +28,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             .expect("erroneous constant missed by mono item collection")
     }
 
-    /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
+    /// This is a convenience helper for `immediate_const_vector`. It has the precondition
     /// that the given `constant` is an `Const::Unevaluated` and must be convertible to
     /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
     ///
@@ -60,23 +59,42 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span)
     }
 
-    /// process constant containing SIMD shuffle indices
-    pub fn simd_shuffle_indices(
+    /// process constant containing SIMD shuffle indices & constant vectors
+    pub fn immediate_const_vector(
         &mut self,
         bx: &Bx,
         constant: &mir::ConstOperand<'tcx>,
     ) -> (Bx::Value, Ty<'tcx>) {
         let ty = self.monomorphize(constant.ty());
+        let ty_is_simd = ty.is_simd();
+        // FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle
+        // in its current form relies on a regular array being passed as an
+        // immediate argument. This hack can be removed once that is fixed.
+        let field_ty = if ty_is_simd {
+            ty.simd_size_and_type(bx.tcx()).1
+        } else {
+            ty.builtin_index().unwrap()
+        };
+
         let val = self
             .eval_unevaluated_mir_constant_to_valtree(constant)
             .ok()
             .map(|x| x.ok())
             .flatten()
             .map(|val| {
-                let field_ty = ty.builtin_index().unwrap();
-                let values: Vec<_> = val
-                    .unwrap_branch()
-                    .iter()
+                // Depending on whether this is a SIMD type with an array field
+                // or a type with many fields (one for each elements), the valtree
+                // is either a single branch with N children, or a root node
+                // with exactly one child which then in turn has many children.
+                // So we look at the first child to determine whether it is a
+                // leaf or whether we have to go one more layer down.
+                let branch_or_leaf = val.unwrap_branch();
+                let first = branch_or_leaf.get(0).unwrap();
+                let field_iter = match first {
+                    ValTree::Branch(_) => first.unwrap_branch().iter(),
+                    ValTree::Leaf(_) => branch_or_leaf.iter(),
+                };
+                let values: Vec<_> = field_iter
                     .map(|field| {
                         if let Some(prim) = field.try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
@@ -85,11 +103,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             };
                             bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
                         } else {
-                            bug!("simd shuffle field {:?}", field)
+                            bug!("field is not a scalar {:?}", field)
                         }
                     })
                     .collect();
-                bx.const_struct(&values, false)
+                if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) }
             })
             .unwrap_or_else(|| {
                 bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
index 72187277228..67f1ef5d944 100644
--- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
@@ -1,9 +1,8 @@
-use crate::traits::*;
-
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::SourceScope;
 
 use super::FunctionCx;
+use crate::traits::*;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn codegen_coverage(&self, bx: &mut Bx, kind: &CoverageKind, scope: SourceScope) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 82ed5610d9e..0e495973a01 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -1,13 +1,11 @@
-use crate::traits::*;
+use std::ops::Range;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::IndexVec;
-use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir;
-use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{Instance, Ty};
+use rustc_middle::{bug, mir, ty};
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{hygiene, BytePos, Span};
@@ -16,8 +14,7 @@ use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx};
 use super::operand::{OperandRef, OperandValue};
 use super::place::{PlaceRef, PlaceValue};
 use super::{FunctionCx, LocalRef};
-
-use std::ops::Range;
+use crate::traits::*;
 
 pub struct FunctionDebugContext<'tcx, S, L> {
     /// Maps from source code to the corresponding debug info scope.
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index f88deaa7abc..4acbc04c505 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -1,21 +1,16 @@
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
+use rustc_session::config::OptLevel;
+use rustc_span::{sym, Span};
+use rustc_target::abi::call::{FnAbi, PassMode};
+use rustc_target::abi::WrappingRange;
+
 use super::operand::OperandRef;
 use super::place::PlaceRef;
 use super::FunctionCx;
-use crate::errors;
 use crate::errors::InvalidMonomorphization;
-use crate::meth;
-use crate::size_of_val;
 use crate::traits::*;
-use crate::MemFlags;
-
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::{bug, span_bug};
-use rustc_session::config::OptLevel;
-use rustc_span::{sym, Span};
-use rustc_target::abi::{
-    call::{FnAbi, PassMode},
-    WrappingRange,
-};
+use crate::{errors, meth, size_of_val, MemFlags};
 
 fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs
index 5190021c005..93f0ab36f2a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/locals.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs
@@ -2,14 +2,16 @@
 //! be careful wrt to subtyping. To deal with this we only allow updates by using
 //! `FunctionCx::overwrite_local` which handles it automatically.
 
-use crate::mir::{FunctionCx, LocalRef};
-use crate::traits::BuilderMethods;
+use std::ops::{Index, IndexMut};
+
 use rustc_index::IndexVec;
 use rustc_middle::mir;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use std::ops::{Index, IndexMut};
 use tracing::{debug, warn};
 
+use crate::mir::{FunctionCx, LocalRef};
+use crate::traits::BuilderMethods;
+
 pub(super) struct Locals<'tcx, V> {
     values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 61f57c9030a..4ce07269cd2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -1,18 +1,17 @@
-use crate::base;
-use crate::traits::*;
+use std::iter;
+
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir;
-use rustc_middle::mir::traversal;
-use rustc_middle::mir::UnwindTerminateReason;
+use rustc_middle::mir::{traversal, UnwindTerminateReason};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_target::abi::call::{FnAbi, PassMode};
 use tracing::{debug, instrument};
 
-use std::iter;
+use crate::base;
+use crate::traits::*;
 
 mod analyze;
 mod block;
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index e08d7a3e826..1891de8c0eb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -1,23 +1,21 @@
-use super::place::{PlaceRef, PlaceValue};
-use super::{FunctionCx, LocalRef};
-
-use crate::size_of_val;
-use crate::traits::*;
-use crate::MemFlags;
+use std::assert_matches::assert_matches;
+use std::fmt;
 
+use arrayvec::ArrayVec;
+use either::Either;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{alloc_range, Pointer, Scalar};
 use rustc_middle::mir::{self, ConstValue};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::Ty;
 use rustc_target::abi::{self, Abi, Align, Size};
-
-use std::fmt;
-
-use arrayvec::ArrayVec;
-use either::Either;
 use tracing::debug;
 
+use super::place::{PlaceRef, PlaceValue};
+use super::{FunctionCx, LocalRef};
+use crate::traits::*;
+use crate::{size_of_val, MemFlags};
+
 /// The representation of a Rust value. The enum variant is in fact
 /// uniquely determined by the value's type, but is kept as a
 /// safety check.
@@ -392,7 +390,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
             }
             // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
             (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => {
-                assert!(matches!(self.layout.abi, Abi::Vector { .. }));
+                assert_matches!(self.layout.abi, Abi::Vector { .. });
 
                 let llfield_ty = bx.cx().backend_type(field);
 
@@ -638,7 +636,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_consume(bx, place.as_ref())
             }
 
-            mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
+            mir::Operand::Constant(ref constant) => {
+                let constant_ty = self.monomorphize(constant.ty());
+                // Most SIMD vector constants should be passed as immediates.
+                // (In particular, some intrinsics really rely on this.)
+                if constant_ty.is_simd() {
+                    // However, some SIMD types do not actually use the vector ABI
+                    // (in particular, packed SIMD types do not). Ensure we exclude those.
+                    let layout = bx.layout_of(constant_ty);
+                    if let Abi::Vector { .. } = layout.abi {
+                        let (llval, ty) = self.immediate_const_vector(bx, constant);
+                        return OperandRef {
+                            val: OperandValue::Immediate(llval),
+                            layout: bx.layout_of(ty),
+                        };
+                    }
+                }
+                self.eval_mir_constant_to_operand(bx, constant)
+            }
         }
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 4394ffb7a1c..0fad4d169ed 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -1,19 +1,18 @@
+use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, Ty};
+use rustc_middle::{bug, mir};
+use rustc_target::abi::{
+    Align, FieldsShape, Int, Pointer, Size, TagEncoding, VariantIdx, Variants,
+};
+use tracing::{debug, instrument};
+
 use super::operand::OperandValue;
 use super::{FunctionCx, LocalRef};
-
 use crate::common::IntPredicate;
 use crate::size_of_val;
 use crate::traits::*;
 
-use rustc_middle::bug;
-use rustc_middle::mir;
-use rustc_middle::mir::tcx::PlaceTy;
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, TagEncoding};
-use rustc_target::abi::{VariantIdx, Variants};
-use tracing::{debug, instrument};
-
 /// The location and extra runtime properties of the place.
 ///
 /// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`].
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 491b457358a..3c2c29ac7f7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -1,23 +1,22 @@
-use super::operand::{OperandRef, OperandValue};
-use super::place::PlaceRef;
-use super::{FunctionCx, LocalRef};
-
-use crate::base;
-use crate::common::IntPredicate;
-use crate::traits::*;
-use crate::MemFlags;
+use std::assert_matches::assert_matches;
 
-use rustc_middle::mir;
+use arrayvec::ArrayVec;
+use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_session::config::OptLevel;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT};
-
-use arrayvec::ArrayVec;
 use tracing::{debug, instrument};
 
+use super::operand::{OperandRef, OperandValue};
+use super::place::PlaceRef;
+use super::{FunctionCx, LocalRef};
+use crate::common::IntPredicate;
+use crate::traits::*;
+use crate::{base, MemFlags};
+
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "trace", skip(self, bx))]
     pub fn codegen_rvalue(
@@ -223,7 +222,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         match operand.val {
             OperandValue::Ref(source_place_val) => {
                 assert_eq!(source_place_val.llextra, None);
-                assert!(matches!(operand_kind, OperandValueKind::Ref));
+                assert_matches!(operand_kind, OperandValueKind::Ref);
                 Some(bx.load_operand(source_place_val.with_type(cast)).val)
             }
             OperandValue::ZeroSized => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 27494f48b09..2ef860fc336 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -3,8 +3,7 @@ use rustc_middle::span_bug;
 use rustc_session::config::OptLevel;
 use tracing::instrument;
 
-use super::FunctionCx;
-use super::LocalRef;
+use super::{FunctionCx, LocalRef};
 use crate::traits::*;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 559ec400577..64fcefdc860 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -1,16 +1,14 @@
-use crate::base;
-use crate::common;
-use crate::traits::*;
 use rustc_hir as hir;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::mir::mono::MonoItem;
-use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::span_bug;
-use rustc_middle::ty;
+use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::Instance;
+use rustc_middle::{span_bug, ty};
 use tracing::debug;
 
+use crate::traits::*;
+use crate::{base, common};
+
 pub trait MonoItemExt<'a, 'tcx> {
     fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
     fn predefine<Bx: BuilderMethods<'a, 'tcx>>(
diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs
index 130fe2eaf2f..933904f9845 100644
--- a/compiler/rustc_codegen_ssa/src/size_of_val.rs
+++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs
@@ -1,9 +1,5 @@
 //! Computing the size and alignment of a value.
 
-use crate::common;
-use crate::common::IntPredicate;
-use crate::meth;
-use crate::traits::*;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
@@ -11,6 +7,10 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::WrappingRange;
 use tracing::{debug, trace};
 
+use crate::common::IntPredicate;
+use crate::traits::*;
+use crate::{common, meth};
+
 pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     t: Ty<'tcx>,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index e7cee5220d6..cf8f7fa25d8 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,26 +1,25 @@
-use crate::errors;
 use rustc_ast::ast;
 use rustc_attr::InstructionSetAttr;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::unord::UnordMap;
+use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
-use rustc_span::symbol::sym;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
+use crate::errors;
+
 pub fn from_target_feature(
     tcx: TyCtxt<'_>,
     attr: &ast::Attribute,
     supported_target_features: &UnordMap<String, Option<Symbol>>,
-    target_features: &mut Vec<Symbol>,
+    target_features: &mut Vec<TargetFeature>,
 ) {
     let Some(list) = attr.meta_item_list() else { return };
     let bad_item = |span| {
@@ -32,6 +31,7 @@ pub fn from_target_feature(
             .emit();
     };
     let rust_features = tcx.features();
+    let mut added_target_features = Vec::new();
     for item in list {
         // Only `enable = ...` is accepted in the meta-item list.
         if !item.has_name(sym::enable) {
@@ -46,7 +46,7 @@ pub fn from_target_feature(
         };
 
         // We allow comma separation to enable multiple features.
-        target_features.extend(value.as_str().split(',').filter_map(|feature| {
+        added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
             let Some(feature_gate) = supported_target_features.get(feature) else {
                 let msg = format!("the feature named `{feature}` is not valid for this target");
                 let mut err = tcx.dcx().struct_span_err(item.span(), msg);
@@ -80,6 +80,7 @@ pub fn from_target_feature(
                 Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
                 Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
                 Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
+                Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86,
                 Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
                 Some(sym::xop_target_feature) => rust_features.xop_target_feature,
                 Some(sym::s390x_target_feature) => rust_features.s390x_target_feature,
@@ -98,6 +99,27 @@ pub fn from_target_feature(
             Some(Symbol::intern(feature))
         }));
     }
+
+    // Add explicit features
+    target_features.extend(
+        added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
+    );
+
+    // Add implied features
+    let mut implied_target_features = UnordSet::new();
+    for feature in added_target_features.iter() {
+        implied_target_features.extend(tcx.implied_target_features(*feature).clone());
+    }
+    for feature in added_target_features.iter() {
+        implied_target_features.remove(feature);
+    }
+    target_features.extend(
+        implied_target_features
+            .into_sorted_stable_ord()
+            .iter()
+            .copied()
+            .map(|name| TargetFeature { name, implied: true }),
+    )
 }
 
 /// Computes the set of target features used in a function for the purposes of
@@ -106,7 +128,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
     let mut target_features = tcx.sess.unstable_target_features.clone();
     if tcx.def_kind(did).has_codegen_attrs() {
         let attrs = tcx.codegen_fn_attrs(did);
-        target_features.extend(&attrs.target_features);
+        target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
         match attrs.instruction_set {
             None => {}
             Some(InstructionSetAttr::ArmA32) => {
@@ -151,10 +173,14 @@ pub(crate) fn provide(providers: &mut Providers) {
                     .target
                     .supported_target_features()
                     .iter()
-                    .map(|&(a, b)| (a.to_string(), b.as_feature_name()))
+                    .map(|&(a, b, _)| (a.to_string(), b.as_feature_name()))
                     .collect()
             }
         },
+        implied_target_features: |tcx, feature| {
+            UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
+                .into_sorted_stable_ord()
+        },
         asm_target_features,
         ..*providers
     }
diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs
index 8d67b626bbd..162141a106b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/asm.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs
@@ -1,12 +1,13 @@
-use super::BackendTypes;
-use crate::mir::operand::OperandRef;
-use crate::mir::place::PlaceRef;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::Instance;
 use rustc_span::Span;
 use rustc_target::asm::InlineAsmRegOrRegClass;
 
+use super::BackendTypes;
+use crate::mir::operand::OperandRef;
+use crate::mir::place::PlaceRef;
+
 #[derive(Debug)]
 pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> {
     In {
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 3770bd11cf9..81e96413a9f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -1,10 +1,5 @@
 use std::any::Any;
 
-use super::write::WriteBackendMethods;
-use super::CodegenObject;
-use crate::back::write::TargetMachineFactoryFn;
-use crate::{CodegenResults, ModuleCodegen};
-
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{DynSend, DynSync};
@@ -15,13 +10,16 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::util::Providers;
-use rustc_session::{
-    config::{self, OutputFilenames, PrintRequest},
-    Session,
-};
+use rustc_session::config::{self, OutputFilenames, PrintRequest};
+use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::call::FnAbi;
 
+use super::write::WriteBackendMethods;
+use super::CodegenObject;
+use crate::back::write::TargetMachineFactoryFn;
+use crate::{CodegenResults, ModuleCodegen};
+
 pub trait BackendTypes {
     type Value: CodegenObject;
     type Function: CodegenObject;
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 42980d9ebd2..6cf84a012f0 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -1,3 +1,14 @@
+use std::assert_matches::assert_matches;
+
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
+use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
+use rustc_middle::ty::{Instance, Ty};
+use rustc_session::config::OptLevel;
+use rustc_span::Span;
+use rustc_target::abi::call::FnAbi;
+use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
+use rustc_target::spec::HasTargetSpec;
+
 use super::abi::AbiBuilderMethods;
 use super::asm::AsmBuilderMethods;
 use super::consts::ConstMethods;
@@ -7,7 +18,6 @@ use super::intrinsic::IntrinsicCallMethods;
 use super::misc::MiscMethods;
 use super::type_::{ArgAbiMethods, BaseTypeMethods, LayoutTypeMethods};
 use super::{HasCodegen, StaticBuilderMethods};
-
 use crate::common::{
     AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
@@ -15,16 +25,7 @@ use crate::mir::operand::{OperandRef, OperandValue};
 use crate::mir::place::{PlaceRef, PlaceValue};
 use crate::MemFlags;
 
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
-use rustc_middle::ty::{Instance, Ty};
-use rustc_session::config::OptLevel;
-use rustc_span::Span;
-use rustc_target::abi::call::FnAbi;
-use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
-use rustc_target::spec::HasTargetSpec;
-
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum OverflowOp {
     Add,
     Sub,
@@ -255,10 +256,10 @@ pub trait BuilderMethods<'a, 'tcx>:
         } else {
             (in_ty, dest_ty)
         };
-        assert!(matches!(
+        assert_matches!(
             self.cx().type_kind(float_ty),
             TypeKind::Half | TypeKind::Float | TypeKind::Double | TypeKind::FP128
-        ));
+        );
         assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
 
         if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts {
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 3da732602c5..c15f1fa8e56 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -1,7 +1,8 @@
-use super::BackendTypes;
 use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
 use rustc_target::abi;
 
+use super::BackendTypes;
+
 pub trait ConstMethods<'tcx>: BackendTypes {
     // Constant constructors
     fn const_null(&self, t: Self::Type) -> Self::Value;
@@ -29,6 +30,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
 
     fn const_str(&self, s: &str) -> (Self::Value, Self::Value);
     fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
+    fn const_vector(&self, elts: &[Self::Value]) -> Self::Value;
 
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
index 906d8b87d3b..0b1645c66ed 100644
--- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
@@ -1,7 +1,8 @@
-use super::BackendTypes;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
 
+use super::BackendTypes;
+
 pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
     /// Performs any start-of-function codegen needed for coverage instrumentation.
     ///
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index 4acc0ea076c..31104e5749b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -1,12 +1,13 @@
-use super::BackendTypes;
-use crate::mir::debuginfo::{FunctionDebugContext, VariableKind};
+use std::ops::Range;
+
 use rustc_middle::mir;
 use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
 use rustc_span::{SourceFile, Span, Symbol};
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Size;
 
-use std::ops::Range;
+use super::BackendTypes;
+use crate::mir::debuginfo::{FunctionDebugContext, VariableKind};
 
 pub trait DebugInfoMethods<'tcx>: BackendTypes {
     fn create_vtable_debuginfo(
diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs
index 655afcd17f0..792d2b04ed6 100644
--- a/compiler/rustc_codegen_ssa/src/traits/declare.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs
@@ -1,8 +1,9 @@
-use super::BackendTypes;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::mono::{Linkage, Visibility};
 use rustc_middle::ty::Instance;
 
+use super::BackendTypes;
+
 pub trait PreDefineMethods<'tcx>: BackendTypes {
     fn predefine_static(
         &self,
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 502f0b3fcb5..172004a9cc7 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -1,9 +1,10 @@
-use super::BackendTypes;
-use crate::mir::operand::OperandRef;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_target::abi::call::FnAbi;
 
+use super::BackendTypes;
+use crate::mir::operand::OperandRef;
+
 pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
     /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`,
     /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics,
diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs
index 0ace28ed3ba..40a49b3e1b5 100644
--- a/compiler/rustc_codegen_ssa/src/traits/misc.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs
@@ -1,9 +1,11 @@
-use super::BackendTypes;
+use std::cell::RefCell;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_session::Session;
-use std::cell::RefCell;
+
+use super::BackendTypes;
 
 pub trait MiscMethods<'tcx>: BackendTypes {
     fn vtables(
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 8cb58bd4c70..9ac923bef88 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -28,6 +28,11 @@ mod statics;
 mod type_;
 mod write;
 
+use std::fmt;
+
+use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt};
+use rustc_target::spec::HasTargetSpec;
+
 pub use self::abi::AbiBuilderMethods;
 pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
 pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
@@ -45,11 +50,6 @@ pub use self::type_::{
 };
 pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
 
-use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt};
-use rustc_target::spec::HasTargetSpec;
-
-use std::fmt;
-
 pub trait CodegenObject: Copy + PartialEq + fmt::Debug {}
 impl<T: Copy + PartialEq + fmt::Debug> CodegenObject for T {}
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs
index 737d93fd80a..b418199e616 100644
--- a/compiler/rustc_codegen_ssa/src/traits/statics.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs
@@ -1,7 +1,8 @@
-use super::BackendTypes;
 use rustc_hir::def_id::DefId;
 use rustc_target::abi::Align;
 
+use super::BackendTypes;
+
 pub trait StaticMethods: BackendTypes {
     fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
     fn codegen_static(&self, def_id: DefId);
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index b1bad6cfa6f..7c042c0c621 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -1,14 +1,14 @@
-use super::misc::MiscMethods;
-use super::Backend;
-use super::HasCodegen;
-use crate::common::TypeKind;
-use crate::mir::place::PlaceRef;
 use rustc_middle::bug;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
 use rustc_target::abi::{AddressSpace, Float, Integer};
 
+use super::misc::MiscMethods;
+use super::{Backend, HasCodegen};
+use crate::common::TypeKind;
+use crate::mir::place::PlaceRef;
+
 // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
 // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
 pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
@@ -91,7 +91,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
             return false;
         }
 
-        let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env);
+        let tail = self.tcx().struct_tail_for_codegen(ty, param_env);
         match tail.kind() {
             ty::Foreign(..) => false,
             ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index f4b1421a532..aabe9e33c4a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -1,10 +1,10 @@
+use rustc_errors::{DiagCtxtHandle, FatalError};
+use rustc_middle::dep_graph::WorkProduct;
+
 use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
 use crate::{CompiledModule, ModuleCodegen};
 
-use rustc_errors::{DiagCtxtHandle, FatalError};
-use rustc_middle::dep_graph::WorkProduct;
-
 pub trait WriteBackendMethods: 'static + Sized + Clone {
     type Module: Send + Sync;
     type TargetMachine;
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index cd269810741..1442f1832b9 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -41,13 +41,15 @@ const_eval_const_context = {$kind ->
     *[other] {""}
 }
 
+const_eval_const_stable = const-stable functions can only call other const-stable functions
+
 const_eval_copy_nonoverlapping_overlapping =
     `copy_nonoverlapping` called on overlapping ranges
 
 const_eval_dangling_int_pointer =
-    {$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance)
+    {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} which is a dangling pointer (it has no provenance)
 const_eval_dangling_null_pointer =
-    {$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance)
+    {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got a null pointer
 
 const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind}
 const_eval_dead_local =
@@ -87,6 +89,21 @@ const_eval_error = {$error_kind ->
 const_eval_exact_div_has_remainder =
     exact_div: {$a} cannot be divided by {$b} without remainder
 
+const_eval_expected_inbounds_pointer =
+    expected a pointer to {$inbounds_size_abs ->
+        [0] some allocation
+        *[x] {$inbounds_size_is_neg ->
+            [false] {$inbounds_size_abs ->
+                    [1] 1 byte of memory
+                    *[x] {$inbounds_size_abs} bytes of memory
+                }
+            *[true] the end of {$inbounds_size_abs ->
+                    [1] 1 byte of memory
+                    *[x] {$inbounds_size_abs} bytes of memory
+                }
+        }
+    }
+
 const_eval_extern_static =
     cannot access extern static ({$did})
 const_eval_extern_type_field = `extern type` field does not have a known offset
@@ -186,6 +203,9 @@ const_eval_invalid_vtable_pointer =
 const_eval_invalid_vtable_trait =
     using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected
 
+const_eval_lazy_lock =
+    consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
+
 const_eval_live_drop =
     destructor of `{$dropped_ty}` cannot be evaluated at compile-time
     .label = the destructor for this type cannot be evaluated in {const_eval_const_context}s
@@ -233,16 +253,17 @@ const_eval_nullary_intrinsic_fail =
 
 const_eval_offset_from_different_allocations =
     `{$name}` called on pointers into different allocations
-const_eval_offset_from_different_integers =
-    `{$name}` called on different pointers without provenance (i.e., without an associated allocation)
 const_eval_offset_from_overflow =
     `{$name}` called when first pointer is too far ahead of second
 const_eval_offset_from_test =
-    out-of-bounds `offset_from`
+    out-of-bounds `offset_from` origin
 const_eval_offset_from_underflow =
     `{$name}` called when first pointer is too far before second
 const_eval_offset_from_unsigned_overflow =
-    `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
+    `ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr ->
+        [true] address
+        *[false] offset
+    } than second: {$a_offset} < {$b_offset}
 
 const_eval_operator_non_const =
     cannot call non-const operator in {const_eval_const_context}s
@@ -261,13 +282,26 @@ const_eval_partial_pointer_copy =
 const_eval_partial_pointer_overwrite =
     unable to overwrite parts of a pointer in memory at {$ptr}
 const_eval_pointer_arithmetic_overflow =
-    overflowing in-bounds pointer arithmetic
+    overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
 const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic
 const_eval_pointer_out_of_bounds =
-    {$bad_pointer_message}: {$alloc_id} has size {$alloc_size}, so pointer to {$ptr_size} {$ptr_size ->
-        [1] byte
-        *[many] bytes
-    } starting at offset {$ptr_offset} is out-of-bounds
+    {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg ->
+        [true] which points to before the beginning of the allocation
+        *[false] {$inbounds_size_is_neg ->
+            [true] {$ptr_offset_abs ->
+                [0] which is at the beginning of the allocation
+                *[other] which does not have enough space to the beginning of the allocation
+            }
+            *[false] {$alloc_size_minus_ptr_offset ->
+                [0] which is at or beyond the end of the allocation of size {$alloc_size ->
+                    [1] 1 byte
+                    *[x] {$alloc_size} bytes
+                }
+                [1] which is only 1 byte from the end of the allocation
+                *[x] which is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
+            }
+        }
+    }
 const_eval_pointer_use_after_free =
     {$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
 const_eval_ptr_as_bytes_1 =
@@ -287,9 +321,6 @@ const_eval_range_upper = less or equal to {$hi}
 const_eval_range_wrapping = less or equal to {$hi}, or greater or equal to {$lo}
 const_eval_raw_bytes = the raw bytes of the constant (size: {$size}, align: {$align}) {"{"}{$bytes}{"}"}
 
-const_eval_raw_eq_with_provenance =
-    `raw_eq` on bytes with provenance
-
 const_eval_raw_ptr_comparison =
     pointers cannot be reliably compared during const eval
     .note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
@@ -465,5 +496,3 @@ const_eval_write_through_immutable_pointer =
 
 const_eval_write_to_read_only =
     writing to {$allocation} which is read-only
-const_eval_zst_pointer_out_of_bounds =
-    {$bad_pointer_message}: {$alloc_id} has size {$alloc_size}, so pointer at offset {$ptr_offset} is out-of-bounds
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 8700ec4c210..844f3f3d611 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -1,5 +1,9 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
+use std::assert_matches::assert_matches;
+use std::mem;
+use std::ops::Deref;
+
 use rustc_errors::{Diag, ErrorGuaranteed};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
@@ -9,17 +13,13 @@ use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
-use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt};
+use rustc_middle::ty::adjustment::PointerCoercion;
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
-
-use std::mem;
-use std::ops::Deref;
-
 use tracing::{debug, instrument, trace};
 
 use super::ops::{self, NonConstOp, Status};
@@ -591,7 +591,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) {
                     // Int, bool, and char operations are fine.
                 } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
-                    assert!(matches!(
+                    assert_matches!(
                         op,
                         BinOp::Eq
                             | BinOp::Ne
@@ -600,7 +600,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             | BinOp::Ge
                             | BinOp::Gt
                             | BinOp::Offset
-                    ));
+                    );
 
                     self.check_op(ops::RawPtrComparison);
                 } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
@@ -635,10 +635,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
         trace!(
             "visit_projection_elem: place_ref={:?} elem={:?} \
             context={:?} location={:?}",
-            place_ref,
-            elem,
-            context,
-            location,
+            place_ref, elem, context, location,
         );
 
         self.super_projection_elem(place_ref, elem, context, location);
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index ac8f0d842ee..15ac4cedcc3 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -4,14 +4,12 @@
 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
 //! it finds operations that are invalid in a certain context.
 
-use rustc_attr as attr;
 use rustc_errors::DiagCtxtHandle;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
+use rustc_middle::{bug, mir};
 use rustc_span::Symbol;
+use {rustc_attr as attr, rustc_hir as hir};
 
 pub use self::qualifs::Qualif;
 
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 55432e63ef9..c6361710ac9 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -2,7 +2,8 @@
 
 use hir::def_id::LocalDefId;
 use hir::{ConstContext, LangItem};
-use rustc_errors::{codes::*, Diag};
+use rustc_errors::codes::*;
+use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -22,7 +23,7 @@ use rustc_trait_selection::traits::SelectionContext;
 use tracing::debug;
 
 use super::ConstCx;
-use crate::errors;
+use crate::{errors, fluent_generated};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
@@ -309,7 +310,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
         }
 
         if let ConstContext::Static(_) = ccx.const_kind() {
-            err.note("consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`");
+            err.note(fluent_generated::const_eval_lazy_lock);
         }
 
         err
@@ -333,7 +334,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
         // FIXME: make this translatable
         #[allow(rustc::untranslatable_diagnostic)]
         if ccx.is_const_stable_const_fn() {
-            err.help("const-stable functions can only call other const-stable functions");
+            err.help(fluent_generated::const_eval_const_stable);
         } else if ccx.tcx.sess.is_nightly_build() {
             if let Some(feature) = feature {
                 err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
@@ -604,8 +605,6 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
             span,
             format!("referencing statics in {}s is unstable", ccx.const_kind(),),
         );
-        // FIXME: make this translatable
-        #[allow(rustc::untranslatable_diagnostic)]
         err
             .note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.")
             .help("to fix this, the value can be extracted to a `const` and then used.");
diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
index f5e745454ab..c4f06e5af0b 100644
--- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
@@ -1,7 +1,8 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
 use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 use tracing::trace;
 
 use super::check::Qualifs;
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index d5d3f7767b1..c0f2d113c7e 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -5,11 +5,10 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
+use rustc_middle::{bug, mir};
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
 };
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 011341472b4..ea3a5264357 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -2,17 +2,16 @@
 //!
 //! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs.
 
+use std::fmt;
+use std::marker::PhantomData;
+
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{
     self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges,
 };
 use rustc_mir_dataflow::fmt::DebugWithContext;
-use rustc_mir_dataflow::JoinSemiLattice;
-use rustc_mir_dataflow::{Analysis, AnalysisDomain};
-
-use std::fmt;
-use std::marker::PhantomData;
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, JoinSemiLattice};
 
 use super::{qualifs, ConstCx, Qualif};
 
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index 9a98677a844..aa7449e8ad2 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -1,14 +1,14 @@
-use crate::interpret::{
-    self, throw_machine_stop, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic,
-};
 use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult};
 use rustc_middle::mir::*;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty};
 use rustc_span::def_id::DefId;
 
+use crate::interpret::{
+    self, throw_machine_stop, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic,
+};
+
 /// Macro for machine-specific `InterpError` without allocation.
 /// (These will never be shown to the user, but they help diagnose ICEs.)
 pub macro throw_machine_stop_str($($tt:tt)*) {{
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index b17dc7f3ddd..00bbd9337f7 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -4,14 +4,15 @@ use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagA
 use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::{layout::LayoutError, ConstInt};
+use rustc_middle::ty::layout::LayoutError;
+use rustc_middle::ty::{ConstInt, TyCtxt};
 use rustc_span::{Span, Symbol};
 
 use super::CompileTimeMachine;
 use crate::errors::{self, FrameNote, ReportErrorExt};
-use crate::interpret::{err_inval, err_machine_stop};
-use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType};
+use crate::interpret::{
+    err_inval, err_machine_stop, ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType,
+};
 
 /// The CTFE machine has some custom error kinds.
 #[derive(Clone, Debug)]
@@ -25,8 +26,9 @@ pub enum ConstEvalErrKind {
 
 impl MachineStopType for ConstEvalErrKind {
     fn diagnostic_message(&self) -> DiagMessage {
-        use crate::fluent_generated::*;
         use ConstEvalErrKind::*;
+
+        use crate::fluent_generated::*;
         match self {
             ConstAccessesMutGlobal => const_eval_const_accesses_mut_global,
             ModifiedGlobal => const_eval_modified_global,
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index d8efaa66415..96b3ec6f187 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -1,8 +1,6 @@
 use std::sync::atomic::Ordering::Relaxed;
 
 use either::{Left, Right};
-use tracing::{debug, instrument, trace};
-
 use rustc_hir::def::DefKind;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
@@ -16,17 +14,16 @@ use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{self, Abi};
+use tracing::{debug, instrument, trace};
 
 use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine};
 use crate::const_eval::CheckAlignment;
-use crate::errors::ConstEvalError;
-use crate::errors::{self, DanglingPtrInFinal};
+use crate::errors::{self, ConstEvalError, DanglingPtrInFinal};
 use crate::interpret::{
-    create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate,
-    InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
-    StackPopCleanup,
+    create_static_alloc, eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust,
+    CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError,
+    InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup,
 };
-use crate::interpret::{eval_nullary_intrinsic, throw_exhaust, InternResult};
 use crate::CTRL_C_RECEIVED;
 
 // Returns a pointer to where the result lives
@@ -76,7 +73,9 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
         cid.promoted.map_or_else(String::new, |p| format!("::{p:?}"))
     );
 
-    ecx.push_stack_frame(
+    // This can't use `init_stack_frame` since `body` is not a function,
+    // so computing its ABI would fail. It's also not worth it since there are no arguments to pass.
+    ecx.push_stack_frame_raw(
         cid.instance,
         body,
         &ret.clone().into(),
@@ -227,7 +226,7 @@ pub(super) fn op_to_const<'tcx>(
                 let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
                 debug_assert!(
                     matches!(
-                        ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(),
+                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.param_env).kind(),
                         ty::Str | ty::Slice(..),
                     ),
                     "`ConstValue::Slice` is for slice-tailed types only, but got {}",
@@ -399,7 +398,7 @@ fn const_validate_mplace<'tcx>(
     let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
     let mut ref_tracking = RefTracking::new(mplace.clone());
     let mut inner = false;
-    while let Some((mplace, path)) = ref_tracking.todo.pop() {
+    while let Some((mplace, path)) = ref_tracking.next() {
         let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
             _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
             Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 7acd08e0cce..ca0993f0580 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -1,10 +1,9 @@
-use rustc_attr as attr;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
+use {rustc_attr as attr, rustc_hir as hir};
 
 /// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
 /// it.
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 17e1d8566c2..a075bdc1911 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -4,18 +4,14 @@ use std::hash::Hash;
 use std::ops::ControlFlow;
 
 use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::fx::IndexEntry;
-use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::LangItem;
-use rustc_hir::{self as hir, CRATE_HIR_ID};
-use rustc_middle::bug;
-use rustc_middle::mir;
+use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{self as hir, LangItem, CRATE_HIR_ID};
 use rustc_middle::mir::AssertMessage;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, mir};
 use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
@@ -23,16 +19,16 @@ use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
 use tracing::debug;
 
+use super::error::*;
 use crate::errors::{LongRunning, LongRunningWarn};
 use crate::fluent_generated as fluent;
 use crate::interpret::{
     self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, throw_unsup,
-    throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, Frame,
+    throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
     GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
+    StackPopCleanup,
 };
 
-use super::error::*;
-
 /// When hitting this many interpreted terminators we emit a deny by default lint
 /// that notfies the user that their constant takes a long time to evaluate. If that's
 /// what they intended, they can just allow the lint.
@@ -201,7 +197,8 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
         let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
         let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
 
-        use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+        use rustc_session::config::RemapPathScopeComponents;
+        use rustc_session::RemapFileNameExt;
         (
             Symbol::intern(
                 &caller
@@ -299,7 +296,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
             );
         }
 
-        match self.ptr_try_get_alloc_id(ptr) {
+        match self.ptr_try_get_alloc_id(ptr, 0) {
             Ok((alloc_id, offset, _extra)) => {
                 let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id);
 
@@ -310,17 +307,15 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
                     let align = ImmTy::from_uint(target_align, args[1].layout).into();
                     let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
-                    // We replace the entire function call with a "tail call".
-                    // Note that this happens before the frame of the original function
-                    // is pushed on the stack.
-                    self.eval_fn_call(
-                        FnVal::Instance(instance),
-                        (CallAbi::Rust, fn_abi),
+                    // Push the stack frame with our own adjusted arguments.
+                    self.init_stack_frame(
+                        instance,
+                        self.load_mir(instance.def, None)?,
+                        fn_abi,
                         &[FnArg::Copy(addr), FnArg::Copy(align)],
                         /* with_caller_location = */ false,
                         dest,
-                        ret,
-                        mir::UnwindAction::Unreachable,
+                        StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable },
                     )?;
                     Ok(ControlFlow::Break(()))
                 } else {
@@ -462,7 +457,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         _unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         // Shared intrinsics.
-        if ecx.emulate_intrinsic(instance, args, dest, target)? {
+        if ecx.eval_intrinsic(instance, args, dest, target)? {
             return Ok(None);
         }
         let intrinsic_name = ecx.tcx.item_name(instance.def_id());
@@ -514,7 +509,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
 
                 // If an allocation is created in an another const,
                 // we don't deallocate it.
-                let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?;
+                let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr, 0)?;
                 let is_allocated_in_another_const = matches!(
                     ecx.tcx.try_get_global_alloc(alloc_id),
                     Some(interpret::GlobalAlloc::Memory(_))
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 3a6dc81eff1..8add23ed22f 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,10 +1,9 @@
 // Not in interpret to make sure we do not use private implementation details
 
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::InterpErrorInfo;
 use rustc_middle::query::{Key, TyCtxtAt};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, mir};
 use rustc_target::abi::VariantIdx;
 use tracing::instrument;
 
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 3bc01510730..460c9797f36 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,9 +1,8 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
+use rustc_middle::{bug, mir};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Abi, VariantIdx};
 use tracing::{debug, instrument, trace};
@@ -13,10 +12,9 @@ use super::machine::CompileTimeInterpCx;
 use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
 use crate::const_eval::CanAccessMutGlobal;
 use crate::errors::MaxNumNodesInConstErr;
-use crate::interpret::MPlaceTy;
 use crate::interpret::{
-    intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy,
-    Projectable, Scalar,
+    intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MPlaceTy, MemPlaceMeta, MemoryKind,
+    PlaceTy, Projectable, Scalar,
 };
 
 #[instrument(skip(ecx), level = "debug")]
@@ -197,7 +195,7 @@ fn reconstruct_place_meta<'tcx>(
 
     let mut last_valtree = valtree;
     // Traverse the type, and update `last_valtree` as we go.
-    let tail = tcx.struct_tail_with_normalize(
+    let tail = tcx.struct_tail_raw(
         layout.ty,
         |ty| ty,
         || {
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 292d6ba9d08..7afb92c08ec 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -1,20 +1,22 @@
 use std::borrow::Cow;
+use std::fmt::Write;
 
 use either::Either;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
+    Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
 };
 use rustc_hir::ConstContext;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::mir::interpret::{
-    CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, Misalignment,
-    PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
-    ValidationErrorInfo,
+    CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpError, InvalidMetaKind,
+    InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo,
+    UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
 };
 use rustc_middle::ty::{self, Mutability, Ty};
 use rustc_span::Span;
 use rustc_target::abi::call::AdjustForForeignAbiError;
-use rustc_target::abi::{Size, WrappingRange};
+use rustc_target::abi::WrappingRange;
 
 use crate::interpret::InternKind;
 
@@ -468,8 +470,9 @@ fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String
 
 impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
     fn diagnostic_message(&self) -> DiagMessage {
-        use crate::fluent_generated::*;
         use UndefinedBehaviorInfo::*;
+
+        use crate::fluent_generated::*;
         match self {
             Ub(msg) => msg.clone().into(),
             Custom(x) => (x.msg)(),
@@ -488,10 +491,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
             UnterminatedCString(_) => const_eval_unterminated_c_string,
             PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
-            PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
             PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
-            DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
-            DanglingIntPointer(_, _) => const_eval_dangling_int_pointer,
+            DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer,
+            DanglingIntPointer { .. } => const_eval_dangling_int_pointer,
             AlignmentCheckFailed { .. } => const_eval_alignment_check_failed,
             WriteToReadOnly(_) => const_eval_write_to_read_only,
             DerefFunctionPointer(_) => const_eval_deref_function_pointer,
@@ -573,18 +575,37 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
                 diag.arg("alloc_id", alloc_id)
                     .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
-            PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
-                diag.arg("alloc_id", alloc_id)
-                    .arg("alloc_size", alloc_size.bytes())
-                    .arg("ptr_offset", ptr_offset)
-                    .arg("ptr_size", ptr_size.bytes())
-                    .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
+            PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
+                diag.arg("alloc_size", alloc_size.bytes());
+                diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
+                diag.arg("pointer", {
+                    let mut out = format!("{:?}", alloc_id);
+                    if ptr_offset > 0 {
+                        write!(out, "+{:#x}", ptr_offset).unwrap();
+                    } else if ptr_offset < 0 {
+                        write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap();
+                    }
+                    out
+                });
+                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
+                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
+                diag.arg("ptr_offset_is_neg", ptr_offset < 0);
+                diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
+                diag.arg(
+                    "alloc_size_minus_ptr_offset",
+                    alloc_size.bytes().saturating_sub(ptr_offset as u64),
+                );
             }
-            DanglingIntPointer(ptr, msg) => {
-                if ptr != 0 {
-                    diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
+            DanglingIntPointer { addr, inbounds_size, msg } => {
+                if addr != 0 {
+                    diag.arg(
+                        "pointer",
+                        Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(),
+                    );
                 }
 
+                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
+                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
                 diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             AlignmentCheckFailed(Misalignment { required, has }, msg) => {
@@ -630,8 +651,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
 
 impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
     fn diagnostic_message(&self) -> DiagMessage {
-        use crate::fluent_generated::*;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
+
+        use crate::fluent_generated::*;
         match self.kind {
             PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
                 const_eval_validation_box_to_uninhabited
@@ -702,9 +724,10 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
     }
 
     fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) {
-        use crate::fluent_generated as fluent;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
 
+        use crate::fluent_generated as fluent;
+
         if let PointerAsInt { .. } | PartialPointer = self.kind {
             err.help(fluent::const_eval_ptr_as_bytes_1);
             err.help(fluent::const_eval_ptr_as_bytes_2);
@@ -835,9 +858,9 @@ impl ReportErrorExt for UnsupportedOpInfo {
         }
     }
     fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
-        use crate::fluent_generated::*;
-
         use UnsupportedOpInfo::*;
+
+        use crate::fluent_generated::*;
         if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
             diag.help(const_eval_ptr_as_bytes_1);
             diag.help(const_eval_ptr_as_bytes_2);
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 56d3dc94104..917a2fa7c6d 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -1,33 +1,24 @@
+//! Manages calling a concrete function (with known MIR body) with argument passing,
+//! and returning the return value to the caller.
+use std::assert_matches::assert_matches;
 use std::borrow::Cow;
 
-use either::Either;
-use tracing::trace;
-
-use rustc_middle::{
-    bug, mir, span_bug,
-    ty::{
-        self,
-        layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout},
-        AdtDef, Instance, Ty,
-    },
-};
-use rustc_span::{source_map::Spanned, sym};
-use rustc_target::abi::{self, FieldIdx};
-use rustc_target::abi::{
-    call::{ArgAbi, FnAbi, PassMode},
-    Integer,
-};
+use either::{Left, Right};
+use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, AdtDef, Instance, Ty};
+use rustc_middle::{bug, mir, span_bug};
+use rustc_span::sym;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::abi::{self, FieldIdx, Integer};
 use rustc_target::spec::abi::Abi;
+use tracing::{info, instrument, trace};
 
 use super::{
     throw_ub, throw_ub_custom, throw_unsup_format, CtfeProvenance, FnVal, ImmTy, InterpCx,
-    InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, Scalar,
-    StackPopCleanup,
-};
-use crate::{
-    fluent_generated as fluent,
-    interpret::{eval_context::StackPopInfo, ReturnAction},
+    InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, ReturnAction, Scalar,
+    StackPopCleanup, StackPopInfo,
 };
+use crate::fluent_generated as fluent;
 
 /// An argment passed to a function.
 #[derive(Clone, Debug)]
@@ -48,15 +39,6 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
     }
 }
 
-struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> {
-    callee: FnVal<'tcx, M::ExtraFnVal>,
-    args: Vec<FnArg<'tcx, M::Provenance>>,
-    fn_sig: ty::FnSig<'tcx>,
-    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
-    /// True if the function is marked as `#[track_caller]` ([`ty::InstanceKind::requires_caller_location`])
-    with_caller_location: bool,
-}
-
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
     /// original memory occurs.
@@ -76,7 +58,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
     }
 
-    pub fn fn_arg_field(
+    /// Helper function for argument untupling.
+    pub(super) fn fn_arg_field(
         &self,
         arg: &FnArg<'tcx, M::Provenance>,
         field: usize,
@@ -87,190 +70,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         })
     }
 
-    pub(super) fn eval_terminator(
-        &mut self,
-        terminator: &mir::Terminator<'tcx>,
-    ) -> InterpResult<'tcx> {
-        use rustc_middle::mir::TerminatorKind::*;
-        match terminator.kind {
-            Return => {
-                self.return_from_current_stack_frame(/* unwinding */ false)?
-            }
-
-            Goto { target } => self.go_to_block(target),
-
-            SwitchInt { ref discr, ref targets } => {
-                let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
-                trace!("SwitchInt({:?})", *discr);
-
-                // Branch to the `otherwise` case by default, if no match is found.
-                let mut target_block = targets.otherwise();
-
-                for (const_int, target) in targets.iter() {
-                    // Compare using MIR BinOp::Eq, to also support pointer values.
-                    // (Avoiding `self.binary_op` as that does some redundant layout computation.)
-                    let res = self.binary_op(
-                        mir::BinOp::Eq,
-                        &discr,
-                        &ImmTy::from_uint(const_int, discr.layout),
-                    )?;
-                    if res.to_scalar().to_bool()? {
-                        target_block = target;
-                        break;
-                    }
-                }
-
-                self.go_to_block(target_block);
-            }
-
-            Call {
-                ref func,
-                ref args,
-                destination,
-                target,
-                unwind,
-                call_source: _,
-                fn_span: _,
-            } => {
-                let old_stack = self.frame_idx();
-                let old_loc = self.frame().loc;
-
-                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
-                    self.eval_callee_and_args(terminator, func, args)?;
-
-                let destination = self.force_allocation(&self.eval_place(destination)?)?;
-                self.eval_fn_call(
-                    callee,
-                    (fn_sig.abi, fn_abi),
-                    &args,
-                    with_caller_location,
-                    &destination,
-                    target,
-                    if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
-                )?;
-                // Sanity-check that `eval_fn_call` either pushed a new frame or
-                // did a jump to another block.
-                if self.frame_idx() == old_stack && self.frame().loc == old_loc {
-                    span_bug!(terminator.source_info.span, "evaluating this call made no progress");
-                }
-            }
-
-            TailCall { ref func, ref args, fn_span: _ } => {
-                let old_frame_idx = self.frame_idx();
-
-                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
-                    self.eval_callee_and_args(terminator, func, args)?;
-
-                self.eval_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
-
-                if self.frame_idx() != old_frame_idx {
-                    span_bug!(
-                        terminator.source_info.span,
-                        "evaluating this tail call pushed a new stack frame"
-                    );
-                }
-            }
-
-            Drop { place, target, unwind, replace: _ } => {
-                let place = self.eval_place(place)?;
-                let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
-                if let ty::InstanceKind::DropGlue(_, None) = instance.def {
-                    // This is the branch we enter if and only if the dropped type has no drop glue
-                    // whatsoever. This can happen as a result of monomorphizing a drop of a
-                    // generic. In order to make sure that generic and non-generic code behaves
-                    // roughly the same (and in keeping with Mir semantics) we do nothing here.
-                    self.go_to_block(target);
-                    return Ok(());
-                }
-                trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty);
-                self.drop_in_place(&place, instance, target, unwind)?;
-            }
-
-            Assert { ref cond, expected, ref msg, target, unwind } => {
-                let ignored =
-                    M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
-                let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
-                if ignored || expected == cond_val {
-                    self.go_to_block(target);
-                } else {
-                    M::assert_panic(self, msg, unwind)?;
-                }
-            }
-
-            UnwindTerminate(reason) => {
-                M::unwind_terminate(self, reason)?;
-            }
-
-            // When we encounter Resume, we've finished unwinding
-            // cleanup for the current stack frame. We pop it in order
-            // to continue unwinding the next frame
-            UnwindResume => {
-                trace!("unwinding: resuming from cleanup");
-                // By definition, a Resume terminator means
-                // that we're unwinding
-                self.return_from_current_stack_frame(/* unwinding */ true)?;
-                return Ok(());
-            }
-
-            // It is UB to ever encounter this.
-            Unreachable => throw_ub!(Unreachable),
-
-            // These should never occur for MIR we actually run.
-            FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | CoroutineDrop => span_bug!(
-                terminator.source_info.span,
-                "{:#?} should have been eliminated by MIR pass",
-                terminator.kind
-            ),
-
-            InlineAsm { template, ref operands, options, ref targets, .. } => {
-                M::eval_inline_asm(self, template, operands, options, targets)?;
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Evaluate the arguments of a function call
-    pub(super) fn eval_fn_call_arguments(
-        &self,
-        ops: &[Spanned<mir::Operand<'tcx>>],
-    ) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> {
-        ops.iter()
-            .map(|op| {
-                let arg = match &op.node {
-                    mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
-                        // Make a regular copy.
-                        let op = self.eval_operand(&op.node, None)?;
-                        FnArg::Copy(op)
-                    }
-                    mir::Operand::Move(place) => {
-                        // If this place lives in memory, preserve its location.
-                        // We call `place_to_op` which will be an `MPlaceTy` whenever there exists
-                        // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
-                        // which can return a local even if that has an mplace.)
-                        let place = self.eval_place(*place)?;
-                        let op = self.place_to_op(&place)?;
-
-                        match op.as_mplace_or_imm() {
-                            Either::Left(mplace) => FnArg::InPlace(mplace),
-                            Either::Right(_imm) => {
-                                // This argument doesn't live in memory, so there's no place
-                                // to make inaccessible during the call.
-                                // We rely on there not being any stray `PlaceTy` that would let the
-                                // caller directly access this local!
-                                // This is also crucial for tail calls, where we want the `FnArg` to
-                                // stay valid when the old stack frame gets popped.
-                                FnArg::Copy(op)
-                            }
-                        }
-                    }
-                };
-
-                Ok(arg)
-            })
-            .collect()
-    }
-
     /// Find the wrapped inner type of a transparent wrapper.
     /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
     ///
@@ -440,8 +239,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         } else {
             trace!(
                 "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
-                caller_abi,
-                callee_abi
+                caller_abi, callee_abi
             );
             return Ok(false);
         }
@@ -513,46 +311,206 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
-    /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
-    /// necessary information about callee and arguments to make a call.
-    fn eval_callee_and_args(
-        &self,
-        terminator: &mir::Terminator<'tcx>,
-        func: &mir::Operand<'tcx>,
-        args: &[Spanned<mir::Operand<'tcx>>],
-    ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
-        let func = self.eval_operand(func, None)?;
-        let args = self.eval_fn_call_arguments(args)?;
-
-        let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
-        let extra_args = &args[fn_sig.inputs().len()..];
-        let extra_args =
-            self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
-
-        let (callee, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
-            ty::FnPtr(_sig) => {
-                let fn_ptr = self.read_pointer(&func)?;
-                let fn_val = self.get_ptr_fn(fn_ptr)?;
-                (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
-            }
-            ty::FnDef(def_id, args) => {
-                let instance = self.resolve(def_id, args)?;
-                (
-                    FnVal::Instance(instance),
-                    self.fn_abi_of_instance(instance, extra_args)?,
-                    instance.def.requires_caller_location(*self.tcx),
+    fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
+        // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
+        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+        if !self.tcx.sess.target.is_like_wasm
+            && attrs
+                .target_features
+                .iter()
+                .any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
+        {
+            throw_ub_custom!(
+                fluent::const_eval_unavailable_target_features_for_fn,
+                unavailable_feats = attrs
+                    .target_features
+                    .iter()
+                    .filter(|&feature| !feature.implied
+                        && !self.tcx.sess.target_features.contains(&feature.name))
+                    .fold(String::new(), |mut s, feature| {
+                        if !s.is_empty() {
+                            s.push_str(", ");
+                        }
+                        s.push_str(feature.name.as_str());
+                        s
+                    }),
+            );
+        }
+        Ok(())
+    }
+
+    /// The main entry point for creating a new stack frame: performs ABI checks and initializes
+    /// arguments.
+    #[instrument(skip(self), level = "trace")]
+    pub fn init_stack_frame(
+        &mut self,
+        instance: Instance<'tcx>,
+        body: &'tcx mir::Body<'tcx>,
+        caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+        args: &[FnArg<'tcx, M::Provenance>],
+        with_caller_location: bool,
+        destination: &MPlaceTy<'tcx, M::Provenance>,
+        mut stack_pop: StackPopCleanup,
+    ) -> InterpResult<'tcx> {
+        // Compute callee information.
+        // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
+        let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
+
+        if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
+            throw_unsup_format!("calling a c-variadic function is not supported");
+        }
+
+        if M::enforce_abi(self) {
+            if caller_fn_abi.conv != callee_fn_abi.conv {
+                throw_ub_custom!(
+                    fluent::const_eval_incompatible_calling_conventions,
+                    callee_conv = format!("{:?}", callee_fn_abi.conv),
+                    caller_conv = format!("{:?}", caller_fn_abi.conv),
                 )
             }
-            _ => {
-                span_bug!(terminator.source_info.span, "invalid callee of type {}", func.layout.ty)
+        }
+
+        // Check that all target features required by the callee (i.e., from
+        // the attribute `#[target_feature(enable = ...)]`) are enabled at
+        // compile time.
+        self.check_fn_target_features(instance)?;
+
+        if !callee_fn_abi.can_unwind {
+            // The callee cannot unwind, so force the `Unreachable` unwind handling.
+            match &mut stack_pop {
+                StackPopCleanup::Root { .. } => {}
+                StackPopCleanup::Goto { unwind, .. } => {
+                    *unwind = mir::UnwindAction::Unreachable;
+                }
             }
-        };
+        }
+
+        self.push_stack_frame_raw(instance, body, destination, stack_pop)?;
+
+        // If an error is raised here, pop the frame again to get an accurate backtrace.
+        // To this end, we wrap it all in a `try` block.
+        let res: InterpResult<'tcx> = try {
+            trace!(
+                "caller ABI: {:#?}, args: {:#?}",
+                caller_fn_abi,
+                args.iter()
+                    .map(|arg| (
+                        arg.layout().ty,
+                        match arg {
+                            FnArg::Copy(op) => format!("copy({op:?})"),
+                            FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
+                        }
+                    ))
+                    .collect::<Vec<_>>()
+            );
+            trace!(
+                "spread_arg: {:?}, locals: {:#?}",
+                body.spread_arg,
+                body.args_iter()
+                    .map(|local| (
+                        local,
+                        self.layout_of_local(self.frame(), local, None).unwrap().ty,
+                    ))
+                    .collect::<Vec<_>>()
+            );
 
-        Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
+            // In principle, we have two iterators: Where the arguments come from, and where
+            // they go to.
+
+            // The "where they come from" part is easy, we expect the caller to do any special handling
+            // that might be required here (e.g. for untupling).
+            // If `with_caller_location` is set we pretend there is an extra argument (that
+            // we will not pass; our `caller_location` intrinsic implementation walks the stack instead).
+            assert_eq!(
+                args.len() + if with_caller_location { 1 } else { 0 },
+                caller_fn_abi.args.len(),
+                "mismatch between caller ABI and caller arguments",
+            );
+            let mut caller_args = args
+                .iter()
+                .zip(caller_fn_abi.args.iter())
+                .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
+
+            // Now we have to spread them out across the callee's locals,
+            // taking into account the `spread_arg`. If we could write
+            // this is a single iterator (that handles `spread_arg`), then
+            // `pass_argument` would be the loop body. It takes care to
+            // not advance `caller_iter` for ignored arguments.
+            let mut callee_args_abis = callee_fn_abi.args.iter();
+            for local in body.args_iter() {
+                // Construct the destination place for this argument. At this point all
+                // locals are still dead, so we cannot construct a `PlaceTy`.
+                let dest = mir::Place::from(local);
+                // `layout_of_local` does more than just the instantiation we need to get the
+                // type, but the result gets cached so this avoids calling the instantiation
+                // query *again* the next time this local is accessed.
+                let ty = self.layout_of_local(self.frame(), local, None)?.ty;
+                if Some(local) == body.spread_arg {
+                    // Make the local live once, then fill in the value field by field.
+                    self.storage_live(local)?;
+                    // Must be a tuple
+                    let ty::Tuple(fields) = ty.kind() else {
+                        span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
+                    };
+                    for (i, field_ty) in fields.iter().enumerate() {
+                        let dest = dest.project_deeper(
+                            &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
+                            *self.tcx,
+                        );
+                        let callee_abi = callee_args_abis.next().unwrap();
+                        self.pass_argument(
+                            &mut caller_args,
+                            callee_abi,
+                            &dest,
+                            field_ty,
+                            /* already_live */ true,
+                        )?;
+                    }
+                } else {
+                    // Normal argument. Cannot mark it as live yet, it might be unsized!
+                    let callee_abi = callee_args_abis.next().unwrap();
+                    self.pass_argument(
+                        &mut caller_args,
+                        callee_abi,
+                        &dest,
+                        ty,
+                        /* already_live */ false,
+                    )?;
+                }
+            }
+            // If the callee needs a caller location, pretend we consume one more argument from the ABI.
+            if instance.def.requires_caller_location(*self.tcx) {
+                callee_args_abis.next().unwrap();
+            }
+            // Now we should have no more caller args or callee arg ABIs
+            assert!(
+                callee_args_abis.next().is_none(),
+                "mismatch between callee ABI and callee body arguments"
+            );
+            if caller_args.next().is_some() {
+                throw_ub_custom!(fluent::const_eval_too_many_caller_args);
+            }
+            // Don't forget to check the return type!
+            if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
+                throw_ub!(AbiMismatchReturn {
+                    caller_ty: caller_fn_abi.ret.layout.ty,
+                    callee_ty: callee_fn_abi.ret.layout.ty
+                });
+            }
+
+            // Protect return place for in-place return value passing.
+            M::protect_in_place_function_argument(self, &destination)?;
+
+            // Don't forget to mark "initially live" locals as live.
+            self.storage_live_for_always_live_locals()?;
+        };
+        res.inspect_err(|_| {
+            // Don't show the incomplete stack frame in the error stacktrace.
+            self.stack_mut().pop();
+        })
     }
 
-    /// Call this function -- pushing the stack frame and initializing the arguments.
+    /// Initiate a call to this function -- pushing the stack frame and initializing the arguments.
     ///
     /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.
     /// However, we also need `caller_abi` to determine if we need to do untupling of arguments.
@@ -560,7 +518,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// `with_caller_location` indicates whether the caller passed a caller location. Miri
     /// implements caller locations without argument passing, but to match `FnAbi` we need to know
     /// when those arguments are present.
-    pub(crate) fn eval_fn_call(
+    pub(super) fn init_fn_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
@@ -568,9 +526,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         with_caller_location: bool,
         destination: &MPlaceTy<'tcx, M::Provenance>,
         target: Option<mir::BasicBlock>,
-        mut unwind: mir::UnwindAction,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
-        trace!("eval_fn_call: {:#?}", fn_val);
+        trace!("init_fn_call: {:#?}", fn_val);
 
         let instance = match fn_val {
             FnVal::Instance(instance) => instance,
@@ -600,8 +558,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     unwind,
                 )? {
                     assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden);
-                    assert!(matches!(fallback.def, ty::InstanceKind::Item(_)));
-                    return self.eval_fn_call(
+                    assert_matches!(fallback.def, ty::InstanceKind::Item(_));
+                    return self.init_fn_call(
                         FnVal::Instance(fallback),
                         (caller_abi, caller_fn_abi),
                         args,
@@ -640,189 +598,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     return Ok(());
                 };
 
-                // Compute callee information using the `instance` returned by
-                // `find_mir_or_eval_fn`.
-                // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
-                let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
-
-                if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
-                    throw_unsup_format!("calling a c-variadic function is not supported");
-                }
-
-                if M::enforce_abi(self) {
-                    if caller_fn_abi.conv != callee_fn_abi.conv {
-                        throw_ub_custom!(
-                            fluent::const_eval_incompatible_calling_conventions,
-                            callee_conv = format!("{:?}", callee_fn_abi.conv),
-                            caller_conv = format!("{:?}", caller_fn_abi.conv),
+                // Special handling for the closure ABI: untuple the last argument.
+                let args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
+                    if caller_abi == Abi::RustCall && !args.is_empty() {
+                        // Untuple
+                        let (untuple_arg, args) = args.split_last().unwrap();
+                        trace!("init_fn_call: Will pass last argument by untupling");
+                        Cow::from(
+                            args.iter()
+                                .map(|a| Ok(a.clone()))
+                                .chain(
+                                    (0..untuple_arg.layout().fields.count())
+                                        .map(|i| self.fn_arg_field(untuple_arg, i)),
+                                )
+                                .collect::<InterpResult<'_, Vec<_>>>()?,
                         )
-                    }
-                }
-
-                // Check that all target features required by the callee (i.e., from
-                // the attribute `#[target_feature(enable = ...)]`) are enabled at
-                // compile time.
-                self.check_fn_target_features(instance)?;
-
-                if !callee_fn_abi.can_unwind {
-                    // The callee cannot unwind, so force the `Unreachable` unwind handling.
-                    unwind = mir::UnwindAction::Unreachable;
-                }
+                    } else {
+                        // Plain arg passing
+                        Cow::from(args)
+                    };
 
-                self.push_stack_frame(
+                self.init_stack_frame(
                     instance,
                     body,
+                    caller_fn_abi,
+                    &args,
+                    with_caller_location,
                     destination,
                     StackPopCleanup::Goto { ret: target, unwind },
-                )?;
-
-                // If an error is raised here, pop the frame again to get an accurate backtrace.
-                // To this end, we wrap it all in a `try` block.
-                let res: InterpResult<'tcx> = try {
-                    trace!(
-                        "caller ABI: {:?}, args: {:#?}",
-                        caller_abi,
-                        args.iter()
-                            .map(|arg| (
-                                arg.layout().ty,
-                                match arg {
-                                    FnArg::Copy(op) => format!("copy({op:?})"),
-                                    FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
-                                }
-                            ))
-                            .collect::<Vec<_>>()
-                    );
-                    trace!(
-                        "spread_arg: {:?}, locals: {:#?}",
-                        body.spread_arg,
-                        body.args_iter()
-                            .map(|local| (
-                                local,
-                                self.layout_of_local(self.frame(), local, None).unwrap().ty,
-                            ))
-                            .collect::<Vec<_>>()
-                    );
-
-                    // In principle, we have two iterators: Where the arguments come from, and where
-                    // they go to.
-
-                    // For where they come from: If the ABI is RustCall, we untuple the
-                    // last incoming argument. These two iterators do not have the same type,
-                    // so to keep the code paths uniform we accept an allocation
-                    // (for RustCall ABI only).
-                    let caller_args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
-                        if caller_abi == Abi::RustCall && !args.is_empty() {
-                            // Untuple
-                            let (untuple_arg, args) = args.split_last().unwrap();
-                            trace!("eval_fn_call: Will pass last argument by untupling");
-                            Cow::from(
-                                args.iter()
-                                    .map(|a| Ok(a.clone()))
-                                    .chain(
-                                        (0..untuple_arg.layout().fields.count())
-                                            .map(|i| self.fn_arg_field(untuple_arg, i)),
-                                    )
-                                    .collect::<InterpResult<'_, Vec<_>>>()?,
-                            )
-                        } else {
-                            // Plain arg passing
-                            Cow::from(args)
-                        };
-                    // If `with_caller_location` is set we pretend there is an extra argument (that
-                    // we will not pass).
-                    assert_eq!(
-                        caller_args.len() + if with_caller_location { 1 } else { 0 },
-                        caller_fn_abi.args.len(),
-                        "mismatch between caller ABI and caller arguments",
-                    );
-                    let mut caller_args = caller_args
-                        .iter()
-                        .zip(caller_fn_abi.args.iter())
-                        .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
-
-                    // Now we have to spread them out across the callee's locals,
-                    // taking into account the `spread_arg`. If we could write
-                    // this is a single iterator (that handles `spread_arg`), then
-                    // `pass_argument` would be the loop body. It takes care to
-                    // not advance `caller_iter` for ignored arguments.
-                    let mut callee_args_abis = callee_fn_abi.args.iter();
-                    for local in body.args_iter() {
-                        // Construct the destination place for this argument. At this point all
-                        // locals are still dead, so we cannot construct a `PlaceTy`.
-                        let dest = mir::Place::from(local);
-                        // `layout_of_local` does more than just the instantiation we need to get the
-                        // type, but the result gets cached so this avoids calling the instantiation
-                        // query *again* the next time this local is accessed.
-                        let ty = self.layout_of_local(self.frame(), local, None)?.ty;
-                        if Some(local) == body.spread_arg {
-                            // Make the local live once, then fill in the value field by field.
-                            self.storage_live(local)?;
-                            // Must be a tuple
-                            let ty::Tuple(fields) = ty.kind() else {
-                                span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
-                            };
-                            for (i, field_ty) in fields.iter().enumerate() {
-                                let dest = dest.project_deeper(
-                                    &[mir::ProjectionElem::Field(
-                                        FieldIdx::from_usize(i),
-                                        field_ty,
-                                    )],
-                                    *self.tcx,
-                                );
-                                let callee_abi = callee_args_abis.next().unwrap();
-                                self.pass_argument(
-                                    &mut caller_args,
-                                    callee_abi,
-                                    &dest,
-                                    field_ty,
-                                    /* already_live */ true,
-                                )?;
-                            }
-                        } else {
-                            // Normal argument. Cannot mark it as live yet, it might be unsized!
-                            let callee_abi = callee_args_abis.next().unwrap();
-                            self.pass_argument(
-                                &mut caller_args,
-                                callee_abi,
-                                &dest,
-                                ty,
-                                /* already_live */ false,
-                            )?;
-                        }
-                    }
-                    // If the callee needs a caller location, pretend we consume one more argument from the ABI.
-                    if instance.def.requires_caller_location(*self.tcx) {
-                        callee_args_abis.next().unwrap();
-                    }
-                    // Now we should have no more caller args or callee arg ABIs
-                    assert!(
-                        callee_args_abis.next().is_none(),
-                        "mismatch between callee ABI and callee body arguments"
-                    );
-                    if caller_args.next().is_some() {
-                        throw_ub_custom!(fluent::const_eval_too_many_caller_args);
-                    }
-                    // Don't forget to check the return type!
-                    if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
-                        throw_ub!(AbiMismatchReturn {
-                            caller_ty: caller_fn_abi.ret.layout.ty,
-                            callee_ty: callee_fn_abi.ret.layout.ty
-                        });
-                    }
-
-                    // Protect return place for in-place return value passing.
-                    M::protect_in_place_function_argument(self, &destination)?;
-
-                    // Don't forget to mark "initially live" locals as live.
-                    self.storage_live_for_always_live_locals()?;
-                };
-                match res {
-                    Err(err) => {
-                        self.stack_mut().pop();
-                        Err(err)
-                    }
-                    Ok(()) => Ok(()),
-                }
+                )
             }
             // `InstanceKind::Virtual` does not have callable MIR. Calls to `Virtual` instances must be
             // codegen'd / interpreted as virtual calls through the vtable.
@@ -875,9 +679,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 } else {
                     // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
                     // (For that reason we also cannot use `unpack_dyn_trait`.)
-                    let receiver_tail = self
-                        .tcx
-                        .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
+                    let receiver_tail =
+                        self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env);
                     let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
                         span_bug!(
                             self.cur_span(),
@@ -945,7 +748,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 caller_fn_abi.args[0].layout.ty = receiver_ty;
 
                 // recurse with concrete function
-                self.eval_fn_call(
+                self.init_fn_call(
                     FnVal::Instance(fn_inst),
                     (caller_abi, &caller_fn_abi),
                     &args,
@@ -958,30 +761,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
-    pub(crate) fn eval_fn_tail_call(
+    /// Initiate a tail call to this function -- popping the current stack frame, pushing the new
+    /// stack frame and initializing the arguments.
+    pub(super) fn init_fn_tail_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
         args: &[FnArg<'tcx, M::Provenance>],
         with_caller_location: bool,
     ) -> InterpResult<'tcx> {
-        trace!("eval_fn_call: {:#?}", fn_val);
+        trace!("init_fn_tail_call: {:#?}", fn_val);
 
         // This is the "canonical" implementation of tails calls,
         // a pop of the current stack frame, followed by a normal call
         // which pushes a new stack frame, with the return address from
         // the popped stack frame.
         //
-        // Note that we are using `pop_stack_frame` and not `return_from_current_stack_frame`,
+        // Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`,
         // as the latter "executes" the goto to the return block, but we don't want to,
         // only the tail called function should return to the current return block.
         M::before_stack_pop(self, self.frame())?;
 
         let StackPopInfo { return_action, return_to_block, return_place } =
-            self.pop_stack_frame(false)?;
+            self.pop_stack_frame_raw(false)?;
 
         assert_eq!(return_action, ReturnAction::Normal);
 
+        // Take the "stack pop cleanup" info, and use that to initiate the next call.
         let StackPopCleanup::Goto { ret, unwind } = return_to_block else {
             bug!("can't tailcall as root");
         };
@@ -990,7 +796,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         //   we should check if both caller&callee can/n't unwind,
         //   see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
 
-        self.eval_fn_call(
+        self.init_fn_call(
             fn_val,
             (caller_abi, caller_fn_abi),
             args,
@@ -1001,41 +807,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         )
     }
 
-    fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
-        // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
-        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-        if !self.tcx.sess.target.is_like_wasm
-            && attrs
-                .target_features
-                .iter()
-                .any(|feature| !self.tcx.sess.target_features.contains(feature))
-        {
-            throw_ub_custom!(
-                fluent::const_eval_unavailable_target_features_for_fn,
-                unavailable_feats = attrs
-                    .target_features
-                    .iter()
-                    .filter(|&feature| !self.tcx.sess.target_features.contains(feature))
-                    .fold(String::new(), |mut s, feature| {
-                        if !s.is_empty() {
-                            s.push_str(", ");
-                        }
-                        s.push_str(feature.as_str());
-                        s
-                    }),
-            );
-        }
-        Ok(())
-    }
-
-    fn drop_in_place(
+    pub(super) fn init_drop_in_place_call(
         &mut self,
         place: &PlaceTy<'tcx, M::Provenance>,
         instance: ty::Instance<'tcx>,
         target: mir::BasicBlock,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
-        trace!("drop_in_place: {:?},\n  instance={:?}", place, instance);
+        trace!("init_drop_in_place_call: {:?},\n  instance={:?}", place, instance);
         // We take the address of the object. This may well be unaligned, which is fine
         // for us here. However, unaligned accesses will probably make the actual drop
         // implementation fail -- a problem shared by rustc.
@@ -1070,7 +849,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let arg = self.mplace_to_ref(&place)?;
         let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?);
 
-        self.eval_fn_call(
+        self.init_fn_call(
             FnVal::Instance(instance),
             (Abi::Rust, fn_abi),
             &[FnArg::Copy(arg.into())],
@@ -1080,4 +859,118 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             unwind,
         )
     }
+
+    /// Pops the current frame from the stack, copies the return value to the caller, deallocates
+    /// the memory for allocated locals, and jumps to an appropriate place.
+    ///
+    /// If `unwinding` is `false`, then we are performing a normal return
+    /// from a function. In this case, we jump back into the frame of the caller,
+    /// and continue execution as normal.
+    ///
+    /// If `unwinding` is `true`, then we are in the middle of a panic,
+    /// and need to unwind this frame. In this case, we jump to the
+    /// `cleanup` block for the function, which is responsible for running
+    /// `Drop` impls for any locals that have been initialized at this point.
+    /// The cleanup block ends with a special `Resume` terminator, which will
+    /// cause us to continue unwinding.
+    #[instrument(skip(self), level = "trace")]
+    pub(super) fn return_from_current_stack_frame(
+        &mut self,
+        unwinding: bool,
+    ) -> InterpResult<'tcx> {
+        info!(
+            "popping stack frame ({})",
+            if unwinding { "during unwinding" } else { "returning from function" }
+        );
+
+        // Check `unwinding`.
+        assert_eq!(
+            unwinding,
+            match self.frame().loc {
+                Left(loc) => self.body().basic_blocks[loc.block].is_cleanup,
+                Right(_) => true,
+            }
+        );
+        if unwinding && self.frame_idx() == 0 {
+            throw_ub_custom!(fluent::const_eval_unwind_past_top);
+        }
+
+        M::before_stack_pop(self, self.frame())?;
+
+        // Copy return value. Must of course happen *before* we deallocate the locals.
+        // Must be *after* `before_stack_pop` as otherwise the return place might still be protected.
+        let copy_ret_result = if !unwinding {
+            let op = self
+                .local_to_op(mir::RETURN_PLACE, None)
+                .expect("return place should always be live");
+            let dest = self.frame().return_place.clone();
+            let res = if self.stack().len() == 1 {
+                // The initializer of constants and statics will get validated separately
+                // after the constant has been fully evaluated. While we could fall back to the default
+                // code path, that will cause -Zenforce-validity to cycle on static initializers.
+                // Reading from a static's memory is not allowed during its evaluation, and will always
+                // trigger a cycle error. Validation must read from the memory of the current item.
+                // For Miri this means we do not validate the root frame return value,
+                // but Miri anyway calls `read_target_isize` on that so separate validation
+                // is not needed.
+                self.copy_op_no_dest_validation(&op, &dest)
+            } else {
+                self.copy_op_allow_transmute(&op, &dest)
+            };
+            trace!("return value: {:?}", self.dump_place(&dest.into()));
+            // We delay actually short-circuiting on this error until *after* the stack frame is
+            // popped, since we want this error to be attributed to the caller, whose type defines
+            // this transmute.
+            res
+        } else {
+            Ok(())
+        };
+
+        // All right, now it is time to actually pop the frame.
+        let stack_pop_info = self.pop_stack_frame_raw(unwinding)?;
+
+        // Report error from return value copy, if any.
+        copy_ret_result?;
+
+        match stack_pop_info.return_action {
+            ReturnAction::Normal => {}
+            ReturnAction::NoJump => {
+                // The hook already did everything.
+                return Ok(());
+            }
+            ReturnAction::NoCleanup => {
+                // If we are not doing cleanup, also skip everything else.
+                assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
+                assert!(!unwinding, "tried to skip cleanup during unwinding");
+                // Skip machine hook.
+                return Ok(());
+            }
+        }
+
+        // Normal return, figure out where to jump.
+        if unwinding {
+            // Follow the unwind edge.
+            match stack_pop_info.return_to_block {
+                StackPopCleanup::Goto { unwind, .. } => {
+                    // This must be the very last thing that happens, since it can in fact push a new stack frame.
+                    self.unwind_to_block(unwind)
+                }
+                StackPopCleanup::Root { .. } => {
+                    panic!("encountered StackPopCleanup::Root when unwinding!")
+                }
+            }
+        } else {
+            // Follow the normal return edge.
+            match stack_pop_info.return_to_block {
+                StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
+                StackPopCleanup::Root { .. } => {
+                    assert!(
+                        self.stack().is_empty(),
+                        "only the bottommost frame can have StackPopCleanup::Root"
+                    );
+                    Ok(())
+                }
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index bd2a5812cfa..37bd6d6e530 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -12,11 +12,10 @@ use rustc_target::abi::Integer;
 use rustc_type_ir::TyKind::*;
 use tracing::trace;
 
+use super::util::ensure_monomorphic_enough;
 use super::{
-    err_inval, throw_ub, throw_ub_custom, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate,
-    InterpCx, Machine, OpTy, PlaceTy,
+    err_inval, throw_ub, throw_ub_custom, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
 };
-
 use crate::fluent_generated as fluent;
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
@@ -387,7 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx> {
         // A<Struct> -> A<Trait> conversion
         let (src_pointee_ty, dest_pointee_ty) =
-            self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env);
+            self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
 
         match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
             (&ty::Array(_, length), &ty::Slice(_)) => {
@@ -401,6 +400,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
             (ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => {
                 let val = self.read_immediate(src)?;
+                // MIR building generates odd NOP casts, prevent them from causing unexpected trouble.
+                // See <https://github.com/rust-lang/rust/issues/128880>.
+                // FIXME: ideally we wouldn't have to do this.
+                if data_a == data_b {
+                    return self.write_immediate(*val, dest);
+                }
                 // Take apart the old pointer, and find the dynamic type.
                 let (old_data, old_vptr) = val.to_scalar_pair();
                 let old_data = old_data.to_pointer(self)?;
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 181c7115386..0008a15722b 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -1,11 +1,9 @@
 //! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines).
 
-use rustc_middle::mir;
-use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
 use rustc_middle::ty::{self, CoroutineArgsExt, ScalarInt, Ty};
-use rustc_target::abi::{self, TagEncoding};
-use rustc_target::abi::{VariantIdx, Variants};
+use rustc_middle::{mir, span_bug};
+use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants};
 use tracing::{instrument, trace};
 
 use super::{
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 9fddeec2973..7a6bbdfdcb5 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1,41 +1,29 @@
-use std::cell::Cell;
-use std::{fmt, mem};
-
-use either::{Either, Left, Right};
-use rustc_infer::infer::at::ToTrace;
-use rustc_infer::traits::ObligationCause;
-use rustc_trait_selection::traits::ObligationCtxt;
-use tracing::{debug, info, info_span, instrument, trace};
-
+use either::{Left, Right};
 use rustc_errors::DiagCtxtHandle;
-use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
-use rustc_index::IndexVec;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::mir;
-use rustc_middle::mir::interpret::{
-    CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo,
-};
+use rustc_infer::traits::ObligationCause;
+use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
-    self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
-    TyAndLayout,
+    self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
-use rustc_middle::{bug, span_bug};
-use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_middle::{mir, span_bug};
 use rustc_session::Limit;
 use rustc_span::Span;
-use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::call::FnAbi;
+use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
+use rustc_trait_selection::traits::ObligationCtxt;
+use tracing::{debug, trace};
 
 use super::{
-    err_inval, throw_inval, throw_ub, throw_ub_custom, throw_unsup, GlobalId, Immediate,
-    InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind,
-    OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance,
-    ReturnAction, Scalar,
+    err_inval, throw_inval, throw_ub, throw_ub_custom, Frame, FrameInfo, GlobalId, InterpErrorInfo,
+    InterpResult, MPlaceTy, Machine, MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic,
+    Projectable, Provenance,
 };
-use crate::errors;
-use crate::util;
-use crate::{fluent_generated as fluent, ReportErrorExt};
+use crate::{fluent_generated as fluent, util, ReportErrorExt};
 
 pub struct InterpCx<'tcx, M: Machine<'tcx>> {
     /// Stores the `Machine` instance.
@@ -58,314 +46,6 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> {
     pub recursion_limit: Limit,
 }
 
-// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
-// boundary and dropped in the other thread, it would exit the span in the other thread.
-struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
-
-impl SpanGuard {
-    /// By default a `SpanGuard` does nothing.
-    fn new() -> Self {
-        Self(tracing::Span::none(), std::marker::PhantomData)
-    }
-
-    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
-    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
-    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
-    /// been pushed.
-    fn enter(&mut self, span: tracing::Span) {
-        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
-        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
-        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
-        // problems.
-        *self = Self(span, std::marker::PhantomData);
-        self.0.with_subscriber(|(id, dispatch)| {
-            dispatch.enter(id);
-        });
-    }
-}
-
-impl Drop for SpanGuard {
-    fn drop(&mut self) {
-        self.0.with_subscriber(|(id, dispatch)| {
-            dispatch.exit(id);
-        });
-    }
-}
-
-/// A stack frame.
-pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
-    ////////////////////////////////////////////////////////////////////////////////
-    // Function and callsite information
-    ////////////////////////////////////////////////////////////////////////////////
-    /// The MIR for the function called on this frame.
-    pub body: &'tcx mir::Body<'tcx>,
-
-    /// The def_id and args of the current function.
-    pub instance: ty::Instance<'tcx>,
-
-    /// Extra data for the machine.
-    pub extra: Extra,
-
-    ////////////////////////////////////////////////////////////////////////////////
-    // Return place and locals
-    ////////////////////////////////////////////////////////////////////////////////
-    /// Work to perform when returning from this function.
-    pub return_to_block: StackPopCleanup,
-
-    /// The location where the result of the current stack frame should be written to,
-    /// and its layout in the caller.
-    pub return_place: MPlaceTy<'tcx, Prov>,
-
-    /// The list of locals for this stack frame, stored in order as
-    /// `[return_ptr, arguments..., variables..., temporaries...]`.
-    /// The locals are stored as `Option<Value>`s.
-    /// `None` represents a local that is currently dead, while a live local
-    /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
-    ///
-    /// Do *not* access this directly; always go through the machine hook!
-    pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
-
-    /// The span of the `tracing` crate is stored here.
-    /// When the guard is dropped, the span is exited. This gives us
-    /// a full stack trace on all tracing statements.
-    tracing_span: SpanGuard,
-
-    ////////////////////////////////////////////////////////////////////////////////
-    // Current position within the function
-    ////////////////////////////////////////////////////////////////////////////////
-    /// If this is `Right`, we are not currently executing any particular statement in
-    /// this frame (can happen e.g. during frame initialization, and during unwinding on
-    /// frames without cleanup code).
-    ///
-    /// Needs to be public because ConstProp does unspeakable things to it.
-    pub loc: Either<mir::Location, Span>,
-}
-
-/// What we store about a frame in an interpreter backtrace.
-#[derive(Clone, Debug)]
-pub struct FrameInfo<'tcx> {
-    pub instance: ty::Instance<'tcx>,
-    pub span: Span,
-}
-
-#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
-pub enum StackPopCleanup {
-    /// Jump to the next block in the caller, or cause UB if None (that's a function
-    /// that may never return). Also store layout of return place so
-    /// we can validate it at that layout.
-    /// `ret` stores the block we jump to on a normal return, while `unwind`
-    /// stores the block used for cleanup during unwinding.
-    Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
-    /// The root frame of the stack: nowhere else to jump to.
-    /// `cleanup` says whether locals are deallocated. Static computation
-    /// wants them leaked to intern what they need (and just throw away
-    /// the entire `ecx` when it is done).
-    Root { cleanup: bool },
-}
-
-/// Return type of [`InterpCx::pop_stack_frame`].
-pub struct StackPopInfo<'tcx, Prov: Provenance> {
-    /// Additional information about the action to be performed when returning from the popped
-    /// stack frame.
-    pub return_action: ReturnAction,
-
-    /// [`return_to_block`](Frame::return_to_block) of the popped stack frame.
-    pub return_to_block: StackPopCleanup,
-
-    /// [`return_place`](Frame::return_place) of the popped stack frame.
-    pub return_place: MPlaceTy<'tcx, Prov>,
-}
-
-/// State of a local variable including a memoized layout
-#[derive(Clone)]
-pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
-    value: LocalValue<Prov>,
-    /// Don't modify if `Some`, this is only used to prevent computing the layout twice.
-    /// Avoids computing the layout of locals that are never actually initialized.
-    layout: Cell<Option<TyAndLayout<'tcx>>>,
-}
-
-impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("LocalState")
-            .field("value", &self.value)
-            .field("ty", &self.layout.get().map(|l| l.ty))
-            .finish()
-    }
-}
-
-/// Current value of a local variable
-///
-/// This does not store the type of the local; the type is given by `body.local_decls` and can never
-/// change, so by not storing here we avoid having to maintain that as an invariant.
-#[derive(Copy, Clone, Debug)] // Miri debug-prints these
-pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
-    /// This local is not currently alive, and cannot be used at all.
-    Dead,
-    /// A normal, live local.
-    /// Mostly for convenience, we re-use the `Operand` type here.
-    /// This is an optimization over just always having a pointer here;
-    /// we can thus avoid doing an allocation when the local just stores
-    /// immediate values *and* never has its address taken.
-    Live(Operand<Prov>),
-}
-
-impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
-    pub fn make_live_uninit(&mut self) {
-        self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
-    }
-
-    /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState`
-    /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type
-    /// private.
-    pub fn as_mplace_or_imm(
-        &self,
-    ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> {
-        match self.value {
-            LocalValue::Dead => None,
-            LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))),
-            LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)),
-        }
-    }
-
-    /// Read the local's value or error if the local is not yet live or not live anymore.
-    #[inline(always)]
-    pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
-        match &self.value {
-            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
-            LocalValue::Live(val) => Ok(val),
-        }
-    }
-
-    /// Overwrite the local. If the local can be overwritten in place, return a reference
-    /// to do so; otherwise return the `MemPlace` to consult instead.
-    #[inline(always)]
-    pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
-        match &mut self.value {
-            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
-            LocalValue::Live(val) => Ok(val),
-        }
-    }
-}
-
-impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
-    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'tcx, Prov, Extra> {
-        Frame {
-            body: self.body,
-            instance: self.instance,
-            return_to_block: self.return_to_block,
-            return_place: self.return_place,
-            locals: self.locals,
-            loc: self.loc,
-            extra,
-            tracing_span: self.tracing_span,
-        }
-    }
-}
-
-impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
-    /// Get the current location within the Frame.
-    ///
-    /// If this is `Right`, we are not currently executing any particular statement in
-    /// this frame (can happen e.g. during frame initialization, and during unwinding on
-    /// frames without cleanup code).
-    ///
-    /// Used by priroda.
-    pub fn current_loc(&self) -> Either<mir::Location, Span> {
-        self.loc
-    }
-
-    /// Return the `SourceInfo` of the current instruction.
-    pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
-        self.loc.left().map(|loc| self.body.source_info(loc))
-    }
-
-    pub fn current_span(&self) -> Span {
-        match self.loc {
-            Left(loc) => self.body.source_info(loc).span,
-            Right(span) => span,
-        }
-    }
-
-    pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
-        // We first try to get a HirId via the current source scope,
-        // and fall back to `body.source`.
-        self.current_source_info()
-            .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
-                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
-                mir::ClearCrossCrate::Clear => None,
-            })
-            .or_else(|| {
-                let def_id = self.body.source.def_id().as_local();
-                def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
-            })
-    }
-
-    /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
-    /// sanity check to detect bugs where we mix up which stack frame a place refers to.
-    #[inline(always)]
-    pub(super) fn locals_addr(&self) -> usize {
-        self.locals.raw.as_ptr().addr()
-    }
-
-    #[must_use]
-    pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec<FrameInfo<'tcx>> {
-        let mut frames = Vec::new();
-        // This deliberately does *not* honor `requires_caller_location` since it is used for much
-        // more than just panics.
-        for frame in stack.iter().rev() {
-            let span = match frame.loc {
-                Left(loc) => {
-                    // If the stacktrace passes through MIR-inlined source scopes, add them.
-                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
-                    let mut scope_data = &frame.body.source_scopes[scope];
-                    while let Some((instance, call_span)) = scope_data.inlined {
-                        frames.push(FrameInfo { span, instance });
-                        span = call_span;
-                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
-                    }
-                    span
-                }
-                Right(span) => span,
-            };
-            frames.push(FrameInfo { span, instance: frame.instance });
-        }
-        trace!("generate stacktrace: {:#?}", frames);
-        frames
-    }
-}
-
-// FIXME: only used by miri, should be removed once translatable.
-impl<'tcx> fmt::Display for FrameInfo<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        ty::tls::with(|tcx| {
-            if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
-                write!(f, "inside closure")
-            } else {
-                // Note: this triggers a `must_produce_diag` state, which means that if we ever
-                // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
-                // we actually want to emit a warning or error to the user.
-                write!(f, "inside `{}`", self.instance)
-            }
-        })
-    }
-}
-
-impl<'tcx> FrameInfo<'tcx> {
-    pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote {
-        let span = self.span;
-        if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
-            errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 }
-        } else {
-            let instance = format!("{}", self.instance);
-            // Note: this triggers a `must_produce_diag` state, which means that if we ever get
-            // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
-            // actually want to emit a warning or error to the user.
-            errors::FrameNote { where_: "instance", span, instance, times: 0 }
-        }
-    }
-}
-
 impl<'tcx, M: Machine<'tcx>> HasDataLayout for InterpCx<'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
@@ -561,17 +241,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.frame().body
     }
 
-    #[inline(always)]
-    pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 {
-        assert!(ty.abi.is_signed());
-        ty.size.sign_extend(value)
-    }
-
-    #[inline(always)]
-    pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 {
-        ty.size.truncate(value)
-    }
-
     #[inline]
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
         ty.is_freeze(*self.tcx, self.param_env)
@@ -715,30 +384,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found")
     }
 
-    #[inline(always)]
-    pub(super) fn layout_of_local(
-        &self,
-        frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
-        local: mir::Local,
-        layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
-        let state = &frame.locals[local];
-        if let Some(layout) = state.layout.get() {
-            return Ok(layout);
-        }
-
-        let layout = from_known_layout(self.tcx, self.param_env, layout, || {
-            let local_ty = frame.body.local_decls[local].ty;
-            let local_ty =
-                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
-            self.layout_of(local_ty)
-        })?;
-
-        // Layouts of locals are requested a lot, so we cache them.
-        state.layout.set(Some(layout));
-        Ok(layout)
-    }
-
     /// Returns the actual dynamic size and alignment of the place at the given type.
     /// Only the "meta" (metadata) part of the place matters.
     /// This can fail to provide an answer for extern types.
@@ -837,132 +482,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.size_and_align_of(&mplace.meta(), &mplace.layout)
     }
 
-    #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
-    pub fn push_stack_frame(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-        body: &'tcx mir::Body<'tcx>,
-        return_place: &MPlaceTy<'tcx, M::Provenance>,
-        return_to_block: StackPopCleanup,
-    ) -> InterpResult<'tcx> {
-        trace!("body: {:#?}", body);
-
-        // First push a stack frame so we have access to the local args
-        self.push_new_stack_frame(instance, body, return_to_block, return_place.clone())?;
-
-        self.after_stack_frame_push(instance, body)?;
-
-        Ok(())
-    }
-
-    /// Creates a new stack frame, initializes it and pushes it onto the stack.
-    /// A private helper for [`push_stack_frame`](InterpCx::push_stack_frame).
-    fn push_new_stack_frame(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-        body: &'tcx mir::Body<'tcx>,
-        return_to_block: StackPopCleanup,
-        return_place: MPlaceTy<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx> {
-        let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
-        let locals = IndexVec::from_elem(dead_local, &body.local_decls);
-        let pre_frame = Frame {
-            body,
-            loc: Right(body.span), // Span used for errors caused during preamble.
-            return_to_block,
-            return_place,
-            locals,
-            instance,
-            tracing_span: SpanGuard::new(),
-            extra: (),
-        };
-        let frame = M::init_frame(self, pre_frame)?;
-        self.stack_mut().push(frame);
-
-        Ok(())
-    }
-
-    /// A private helper for [`push_stack_frame`](InterpCx::push_stack_frame).
-    fn after_stack_frame_push(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-        body: &'tcx mir::Body<'tcx>,
-    ) -> InterpResult<'tcx> {
-        // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
-        for &const_ in &body.required_consts {
-            let c =
-                self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
-            c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
-                err.emit_note(*self.tcx);
-                err
-            })?;
-        }
-
-        // done
-        M::after_stack_push(self)?;
-        self.frame_mut().loc = Left(mir::Location::START);
-
-        let span = info_span!("frame", "{}", instance);
-        self.frame_mut().tracing_span.enter(span);
-
-        Ok(())
-    }
-
-    /// Pops a stack frame from the stack and returns some information about it.
-    ///
-    /// This also deallocates locals, if necessary.
-    ///
-    /// [`M::before_stack_pop`] should be called before calling this function.
-    /// [`M::after_stack_pop`] is called by this function automatically.
-    ///
-    /// [`M::before_stack_pop`]: Machine::before_stack_pop
-    /// [`M::after_stack_pop`]: Machine::after_stack_pop
-    pub fn pop_stack_frame(
-        &mut self,
-        unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
-        let cleanup = self.cleanup_current_frame_locals()?;
-
-        let frame =
-            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
-
-        let return_to_block = frame.return_to_block;
-        let return_place = frame.return_place.clone();
-
-        let return_action;
-        if cleanup {
-            return_action = M::after_stack_pop(self, frame, unwinding)?;
-            assert_ne!(return_action, ReturnAction::NoCleanup);
-        } else {
-            return_action = ReturnAction::NoCleanup;
-        };
-
-        Ok(StackPopInfo { return_action, return_to_block, return_place })
-    }
-
-    /// A private helper for [`pop_stack_frame`](InterpCx::pop_stack_frame).
-    /// Returns `true` if cleanup has been done, `false` otherwise.
-    fn cleanup_current_frame_locals(&mut self) -> InterpResult<'tcx, bool> {
-        // Cleanup: deallocate locals.
-        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
-        // We do this while the frame is still on the stack, so errors point to the callee.
-        let return_to_block = self.frame().return_to_block;
-        let cleanup = match return_to_block {
-            StackPopCleanup::Goto { .. } => true,
-            StackPopCleanup::Root { cleanup, .. } => cleanup,
-        };
-
-        if cleanup {
-            // We need to take the locals out, since we need to mutate while iterating.
-            let locals = mem::take(&mut self.frame_mut().locals);
-            for local in &locals {
-                self.deallocate_local(local.value)?;
-            }
-        }
-
-        Ok(cleanup)
-    }
-
     /// Jump to the given block.
     #[inline]
     pub fn go_to_block(&mut self, target: mir::BasicBlock) {
@@ -1009,248 +528,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
-    /// Pops the current frame from the stack, deallocating the
-    /// memory for allocated locals, and jumps to an appropriate place.
-    ///
-    /// If `unwinding` is `false`, then we are performing a normal return
-    /// from a function. In this case, we jump back into the frame of the caller,
-    /// and continue execution as normal.
-    ///
-    /// If `unwinding` is `true`, then we are in the middle of a panic,
-    /// and need to unwind this frame. In this case, we jump to the
-    /// `cleanup` block for the function, which is responsible for running
-    /// `Drop` impls for any locals that have been initialized at this point.
-    /// The cleanup block ends with a special `Resume` terminator, which will
-    /// cause us to continue unwinding.
-    #[instrument(skip(self), level = "debug")]
-    pub(super) fn return_from_current_stack_frame(
-        &mut self,
-        unwinding: bool,
-    ) -> InterpResult<'tcx> {
-        info!(
-            "popping stack frame ({})",
-            if unwinding { "during unwinding" } else { "returning from function" }
-        );
-
-        // Check `unwinding`.
-        assert_eq!(
-            unwinding,
-            match self.frame().loc {
-                Left(loc) => self.body().basic_blocks[loc.block].is_cleanup,
-                Right(_) => true,
-            }
-        );
-        if unwinding && self.frame_idx() == 0 {
-            throw_ub_custom!(fluent::const_eval_unwind_past_top);
-        }
-
-        M::before_stack_pop(self, self.frame())?;
-
-        // Copy return value. Must of course happen *before* we deallocate the locals.
-        let copy_ret_result = if !unwinding {
-            let op = self
-                .local_to_op(mir::RETURN_PLACE, None)
-                .expect("return place should always be live");
-            let dest = self.frame().return_place.clone();
-            let err = if self.stack().len() == 1 {
-                // The initializer of constants and statics will get validated separately
-                // after the constant has been fully evaluated. While we could fall back to the default
-                // code path, that will cause -Zenforce-validity to cycle on static initializers.
-                // Reading from a static's memory is not allowed during its evaluation, and will always
-                // trigger a cycle error. Validation must read from the memory of the current item.
-                // For Miri this means we do not validate the root frame return value,
-                // but Miri anyway calls `read_target_isize` on that so separate validation
-                // is not needed.
-                self.copy_op_no_dest_validation(&op, &dest)
-            } else {
-                self.copy_op_allow_transmute(&op, &dest)
-            };
-            trace!("return value: {:?}", self.dump_place(&dest.into()));
-            // We delay actually short-circuiting on this error until *after* the stack frame is
-            // popped, since we want this error to be attributed to the caller, whose type defines
-            // this transmute.
-            err
-        } else {
-            Ok(())
-        };
-
-        // All right, now it is time to actually pop the frame.
-        let stack_pop_info = self.pop_stack_frame(unwinding)?;
-
-        // Report error from return value copy, if any.
-        copy_ret_result?;
-
-        match stack_pop_info.return_action {
-            ReturnAction::Normal => {}
-            ReturnAction::NoJump => {
-                // The hook already did everything.
-                return Ok(());
-            }
-            ReturnAction::NoCleanup => {
-                // If we are not doing cleanup, also skip everything else.
-                assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
-                assert!(!unwinding, "tried to skip cleanup during unwinding");
-                // Skip machine hook.
-                return Ok(());
-            }
-        }
-
-        // Normal return, figure out where to jump.
-        if unwinding {
-            // Follow the unwind edge.
-            let unwind = match stack_pop_info.return_to_block {
-                StackPopCleanup::Goto { unwind, .. } => unwind,
-                StackPopCleanup::Root { .. } => {
-                    panic!("encountered StackPopCleanup::Root when unwinding!")
-                }
-            };
-            // This must be the very last thing that happens, since it can in fact push a new stack frame.
-            self.unwind_to_block(unwind)
-        } else {
-            // Follow the normal return edge.
-            match stack_pop_info.return_to_block {
-                StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
-                StackPopCleanup::Root { .. } => {
-                    assert!(
-                        self.stack().is_empty(),
-                        "only the topmost frame can have StackPopCleanup::Root"
-                    );
-                    Ok(())
-                }
-            }
-        }
-    }
-
-    /// In the current stack frame, mark all locals as live that are not arguments and don't have
-    /// `Storage*` annotations (this includes the return place).
-    pub fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> {
-        self.storage_live(mir::RETURN_PLACE)?;
-
-        let body = self.body();
-        let always_live = always_storage_live_locals(body);
-        for local in body.vars_and_temps_iter() {
-            if always_live.contains(local) {
-                self.storage_live(local)?;
-            }
-        }
-        Ok(())
-    }
-
-    pub fn storage_live_dyn(
-        &mut self,
-        local: mir::Local,
-        meta: MemPlaceMeta<M::Provenance>,
-    ) -> InterpResult<'tcx> {
-        trace!("{:?} is now live", local);
-
-        // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs.
-        fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
-            match ty.kind() {
-                ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-                | ty::Uint(_)
-                | ty::Int(_)
-                | ty::Bool
-                | ty::Float(_)
-                | ty::FnDef(..)
-                | ty::FnPtr(_)
-                | ty::RawPtr(..)
-                | ty::Char
-                | ty::Ref(..)
-                | ty::Coroutine(..)
-                | ty::CoroutineWitness(..)
-                | ty::Array(..)
-                | ty::Closure(..)
-                | ty::CoroutineClosure(..)
-                | ty::Never
-                | ty::Error(_)
-                | ty::Dynamic(_, _, ty::DynStar) => true,
-
-                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
-
-                ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
-
-                ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
-
-                // We don't want to do any queries, so there is not much we can do with ADTs.
-                ty::Adt(..) => false,
-
-                ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
-
-                ty::Infer(ty::TyVar(_)) => false,
-
-                ty::Bound(..)
-                | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-                    bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
-                }
-            }
-        }
-
-        // This is a hot function, we avoid computing the layout when possible.
-        // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types.
-        let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) {
-            None
-        } else {
-            // We need the layout.
-            let layout = self.layout_of_local(self.frame(), local, None)?;
-            if layout.is_sized() { None } else { Some(layout) }
-        };
-
-        let local_val = LocalValue::Live(if let Some(layout) = unsized_ {
-            if !meta.has_meta() {
-                throw_unsup!(UnsizedLocal);
-            }
-            // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized.
-            let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
-            Operand::Indirect(*dest_place.mplace())
-        } else {
-            assert!(!meta.has_meta()); // we're dropping the metadata
-            // Just make this an efficient immediate.
-            // Note that not calling `layout_of` here does have one real consequence:
-            // if the type is too big, we'll only notice this when the local is actually initialized,
-            // which is a bit too late -- we should ideally notice this already here, when the memory
-            // is conceptually allocated. But given how rare that error is and that this is a hot function,
-            // we accept this downside for now.
-            Operand::Immediate(Immediate::Uninit)
-        });
-
-        // If the local is already live, deallocate its old memory.
-        let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
-        self.deallocate_local(old)?;
-        Ok(())
-    }
-
-    /// Mark a storage as live, killing the previous content.
-    #[inline(always)]
-    pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
-        self.storage_live_dyn(local, MemPlaceMeta::None)
-    }
-
-    pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
-        assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
-        trace!("{:?} is now dead", local);
-
-        // If the local is already dead, this is a NOP.
-        let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
-        self.deallocate_local(old)?;
-        Ok(())
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
-        if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
-            // All locals have a backing allocation, even if the allocation is empty
-            // due to the local having ZST type. Hence we can `unwrap`.
-            trace!(
-                "deallocating local {:?}: {:?}",
-                local,
-                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
-                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
-            );
-            self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
-        };
-        Ok(())
-    }
-
     /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals.
     /// (`mir::Const`/`ty::Const` have `eval` methods that can be used directly instead.)
     pub fn ctfe_query<T>(
@@ -1340,39 +617,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for PlacePrinter<'a, 'tcx, M> {
                 }
                 write!(fmt, ":")?;
 
-                match self.ecx.frame().locals[local].value {
-                    LocalValue::Dead => write!(fmt, " is dead")?,
-                    LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
-                        write!(fmt, " is uninitialized")?
-                    }
-                    LocalValue::Live(Operand::Indirect(mplace)) => {
-                        write!(
-                            fmt,
-                            " by {} ref {:?}:",
-                            match mplace.meta {
-                                MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"),
-                                MemPlaceMeta::None => String::new(),
-                            },
-                            mplace.ptr,
-                        )?;
-                        allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
-                    }
-                    LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
-                        write!(fmt, " {val:?}")?;
-                        if let Scalar::Ptr(ptr, _size) = val {
-                            allocs.push(ptr.provenance.get_alloc_id());
-                        }
-                    }
-                    LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
-                        write!(fmt, " ({val1:?}, {val2:?})")?;
-                        if let Scalar::Ptr(ptr, _size) = val1 {
-                            allocs.push(ptr.provenance.get_alloc_id());
-                        }
-                        if let Scalar::Ptr(ptr, _size) = val2 {
-                            allocs.push(ptr.provenance.get_alloc_id());
-                        }
-                    }
-                }
+                self.ecx.frame().locals[local].print(&mut allocs, fmt)?;
 
                 write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect()))
             }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index b227565f8f9..3be1b745d00 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -2,27 +2,24 @@
 //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
 //! and miri.
 
+use std::assert_matches::assert_matches;
+
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty;
-use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_middle::{
-    bug,
-    mir::{self, BinOp, ConstValue, NonDivergingIntrinsic},
-    ty::layout::TyAndLayout,
-};
+use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
+use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement};
+use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt};
+use rustc_middle::{bug, ty};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::Size;
 use tracing::trace;
 
+use super::memory::MemoryKind;
+use super::util::ensure_monomorphic_enough;
 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,
-    Provenance, Scalar,
+    err_inval, err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format,
+    Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult,
+    MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar,
 };
-
 use crate::fluent_generated as fluent;
 
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
@@ -102,7 +99,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Returns `true` if emulation happened.
     /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
     /// intrinsic handling.
-    pub fn emulate_intrinsic(
+    pub fn eval_intrinsic(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::Provenance>],
@@ -211,7 +208,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 } else {
                     (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
                 };
-                let truncated_bits = self.truncate(result_bits, layout_val);
+                let truncated_bits = layout_val.size.truncate(result_bits);
                 let result = Scalar::from_uint(truncated_bits, layout_val.size);
                 self.write_scalar(result, dest)?;
             }
@@ -243,36 +240,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let isize_layout = self.layout_of(self.tcx.types.isize)?;
 
                 // Get offsets for both that are at least relative to the same base.
-                let (a_offset, b_offset) =
-                    match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
+                // With `OFFSET_IS_ADDR` this is trivial; without it we need either
+                // two integers or two pointers into the same allocation.
+                let (a_offset, b_offset, is_addr) = if M::Provenance::OFFSET_IS_ADDR {
+                    (a.addr().bytes(), b.addr().bytes(), /*is_addr*/ true)
+                } else {
+                    match (self.ptr_try_get_alloc_id(a, 0), self.ptr_try_get_alloc_id(b, 0)) {
                         (Err(a), Err(b)) => {
-                            // Neither pointer points to an allocation.
-                            // This is okay only if they are the same.
-                            if a != b {
-                                // We'd catch this below in the "dereferenceable" check, but
-                                // show a nicer error for this particular case.
-                                throw_ub_custom!(
-                                    fluent::const_eval_offset_from_different_integers,
-                                    name = intrinsic_name,
-                                );
-                            }
-                            // This will always return 0.
-                            (a, b)
-                        }
-                        _ 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)
+                            // Neither pointer points to an allocation, so they are both absolute.
+                            (a, b, /*is_addr*/ true)
                         }
-                        // 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())
+                            (a_offset.bytes(), b_offset.bytes(), /*is_addr*/ false)
                         }
                         _ => {
                             // Not into the same allocation -- this is UB.
@@ -281,9 +264,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                                 name = intrinsic_name,
                             );
                         }
-                    };
+                    }
+                };
 
-                // Compute distance.
+                // Compute distance: a - b.
                 let dist = {
                     // Addresses are unsigned, so this is a `usize` computation. We have to do the
                     // overflow check separately anyway.
@@ -300,6 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                                 fluent::const_eval_offset_from_unsigned_overflow,
                                 a_offset = a_offset,
                                 b_offset = b_offset,
+                                is_addr = is_addr,
                             );
                         }
                         // The signed form of the intrinsic allows this. If we interpret the
@@ -328,14 +313,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     }
                 };
 
-                // Check that the range between them is dereferenceable ("in-bounds or one past the
-                // end of the same allocation"). This is like the check in ptr_offset_inbounds.
-                let min_ptr = if dist >= 0 { b } else { a };
-                self.check_ptr_access(
-                    min_ptr,
-                    Size::from_bytes(dist.unsigned_abs()),
+                // Check that the memory between them is dereferenceable at all, starting from the
+                // origin pointer: `dist` is `a - b`, so it is based on `b`.
+                self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?;
+                // Then check that this is also dereferenceable from `a`. This ensures that they are
+                // derived from the same allocation.
+                self.check_ptr_access_signed(
+                    a,
+                    dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large
                     CheckInAllocMsg::OffsetFromTest,
-                )?;
+                )
+                .map_err(|_| {
+                    // Make the error more specific.
+                    err_ub_custom!(
+                        fluent::const_eval_offset_from_different_allocations,
+                        name = intrinsic_name,
+                    )
+                })?;
 
                 // Perform division by size to compute return value.
                 let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
@@ -455,7 +449,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(true)
     }
 
-    pub(super) fn emulate_nondiverging_intrinsic(
+    pub(super) fn eval_nondiverging_intrinsic(
         &mut self,
         intrinsic: &NonDivergingIntrinsic<'tcx>,
     ) -> InterpResult<'tcx> {
@@ -518,7 +512,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         dest: &MPlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         assert_eq!(a.layout.ty, b.layout.ty);
-        assert!(matches!(a.layout.ty.kind(), ty::Int(..) | ty::Uint(..)));
+        assert_matches!(a.layout.ty.kind(), ty::Int(..) | ty::Uint(..));
 
         // Performs an exact division, resulting in undefined behavior where
         // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
@@ -544,8 +538,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         r: &ImmTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         assert_eq!(l.layout.ty, r.layout.ty);
-        assert!(matches!(l.layout.ty.kind(), ty::Int(..) | ty::Uint(..)));
-        assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
+        assert_matches!(l.layout.ty.kind(), ty::Int(..) | ty::Uint(..));
+        assert_matches!(mir_op, BinOp::Add | BinOp::Sub);
 
         let (val, overflowed) =
             self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair();
@@ -582,27 +576,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     }
 
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
-    /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
-    /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
+    /// allocation.
     pub fn ptr_offset_inbounds(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
         offset_bytes: i64,
     ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
-        // The offset being in bounds cannot rely on "wrapping around" the address space.
-        // So, first rule out overflows in the pointer arithmetic.
-        let offset_ptr = ptr.signed_offset(offset_bytes, self)?;
-        // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the
-        // memory between these pointers must be accessible. Note that we do not require the
-        // pointers to be properly aligned (unlike a read/write operation).
-        let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
-        // This call handles checking for integer/null pointers.
-        self.check_ptr_access(
-            min_ptr,
-            Size::from_bytes(offset_bytes.unsigned_abs()),
-            CheckInAllocMsg::PointerArithmeticTest,
-        )?;
-        Ok(offset_ptr)
+        // The offset must be in bounds starting from `ptr`.
+        self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?;
+        // This also implies that there is no overflow, so we are done.
+        Ok(ptr.wrapping_signed_offset(offset_bytes, self))
     }
 
     /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.
@@ -709,9 +692,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // zero-sized access
                 return Ok(&[]);
             };
-            if alloc_ref.has_provenance() {
-                throw_ub_custom!(fluent::const_eval_raw_eq_with_provenance);
-            }
             alloc_ref.get_bytes_strip_provenance()
         };
 
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 7f2e9ce06a5..761ab81e228 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -8,10 +8,9 @@ use std::hash::Hash;
 
 use rustc_apfloat::{Float, FloatConvert};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
-use rustc_middle::mir;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::{mir, ty};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_target::abi::{Align, Size};
@@ -20,7 +19,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
 use super::{
     throw_unsup, throw_unsup_format, AllocBytes, AllocId, AllocKind, AllocRange, Allocation,
     ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy,
-    MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
+    MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance, CTFE_ALLOC_SALT,
 };
 
 /// Data returned by [`Machine::after_stack_pop`], and consumed by
@@ -38,7 +37,7 @@ pub enum ReturnAction {
     /// took care of everything.
     NoJump,
 
-    /// Returned by [`InterpCx::pop_stack_frame`] when no cleanup should be done.
+    /// Returned by [`InterpCx::pop_stack_frame_raw`] when no cleanup should be done.
     NoCleanup,
 }
 
@@ -166,6 +165,13 @@ pub trait Machine<'tcx>: Sized {
 
     /// Whether to enforce the validity invariant for a specific layout.
     fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;
+    /// Whether to enforce the validity invariant *recursively*.
+    fn enforce_validity_recursively(
+        _ecx: &InterpCx<'tcx, Self>,
+        _layout: TyAndLayout<'tcx>,
+    ) -> bool {
+        false
+    }
 
     /// Whether function calls should be [ABI](CallAbi)-checked.
     fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool {
@@ -322,15 +328,21 @@ pub trait Machine<'tcx>: Sized {
         ptr: Pointer<Self::Provenance>,
     ) -> InterpResult<'tcx>;
 
-    /// Convert a pointer with provenance into an allocation-offset pair
-    /// and extra provenance info.
+    /// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.
+    /// `size` says how many bytes of memory are expected at that pointer. The *sign* of `size` can
+    /// be used to disambiguate situations where a wildcard pointer sits right in between two
+    /// allocations.
     ///
-    /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
+    /// If `ptr.provenance.get_alloc_id()` is `Some(p)`, the returned `AllocId` must be `p`.
+    /// The resulting `AllocId` will just be used for that one step and the forgotten again
+    /// (i.e., we'll never turn the data returned here back into a `Pointer` that might be
+    /// stored in machine state).
     ///
     /// When this fails, that means the pointer does not point to a live allocation.
     fn ptr_get_alloc(
         ecx: &InterpCx<'tcx, Self>,
         ptr: Pointer<Self::Provenance>,
+        size: i64,
     ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
 
     /// Called to adjust global allocations to the Provenance and AllocExtra of this machine.
@@ -563,6 +575,14 @@ pub trait Machine<'tcx>: Sized {
     {
         eval(ecx, val, span, layout)
     }
+
+    /// Returns the salt to be used for a deduplicated global alloation.
+    /// If the allocation is for a function, the instance is provided as well
+    /// (this lets Miri ensure unique addresses for some functions).
+    fn get_global_alloc_salt(
+        ecx: &InterpCx<'tcx, Self>,
+        instance: Option<ty::Instance<'tcx>>,
+    ) -> usize;
 }
 
 /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
@@ -659,9 +679,18 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
     fn ptr_get_alloc(
         _ecx: &InterpCx<$tcx, Self>,
         ptr: Pointer<CtfeProvenance>,
+        _size: i64,
     ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
         // We know `offset` is relative to the allocation, so we can use `into_parts`.
         let (prov, offset) = ptr.into_parts();
         Some((prov.alloc_id(), offset, prov.immutable()))
     }
+
+    #[inline(always)]
+    fn get_global_alloc_salt(
+        _ecx: &InterpCx<$tcx, Self>,
+        _instance: Option<ty::Instance<$tcx>>,
+    ) -> usize {
+        CTFE_ALLOC_SALT
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 36fe8dfdd29..910aec9b8e1 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -10,8 +10,7 @@ use std::assert_matches::assert_matches;
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::collections::VecDeque;
-use std::fmt;
-use std::ptr;
+use std::{fmt, ptr};
 
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
@@ -20,17 +19,15 @@ use rustc_middle::bug;
 use rustc_middle::mir::display_allocation;
 use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size};
-
 use tracing::{debug, instrument, trace};
 
-use crate::fluent_generated as fluent;
-
 use super::{
     alloc_range, err_ub, err_ub_custom, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
     AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
     CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
     PointerArithmetic, Provenance, Scalar,
 };
+use crate::fluent_generated as fluent;
 
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub enum MemoryKind<T> {
@@ -198,7 +195,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     pub fn fn_ptr(&mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>) -> Pointer<M::Provenance> {
         let id = match fn_val {
-            FnVal::Instance(instance) => self.tcx.reserve_and_set_fn_alloc(instance),
+            FnVal::Instance(instance) => {
+                let salt = M::get_global_alloc_salt(self, Some(instance));
+                self.tcx.reserve_and_set_fn_alloc(instance, salt)
+            }
             FnVal::Other(extra) => {
                 // FIXME(RalfJung): Should we have a cache here?
                 let id = self.tcx.reserve_alloc_id();
@@ -264,7 +264,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         new_align: Align,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
-        let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
         if offset.bytes() != 0 {
             throw_ub_custom!(
                 fluent::const_eval_realloc_or_alloc_with_offset,
@@ -294,7 +294,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         old_size_and_align: Option<(Size, Align)>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx> {
-        let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr, 0)?;
         trace!("deallocating: {alloc_id:?}");
 
         if offset.bytes() != 0 {
@@ -386,6 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         ptr: Pointer<Option<M::Provenance>>,
         size: Size,
     ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
+        let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
         self.check_and_deref_ptr(
             ptr,
             size,
@@ -407,6 +408,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: Size,
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx> {
+        let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
+        self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| {
+            let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
+            Ok((size, align, ()))
+        })?;
+        Ok(())
+    }
+
+    /// Check whether the given pointer points to live memory for a signed amount of bytes.
+    /// A negative amounts means that the given range of memory to the left of the pointer
+    /// needs to be dereferenceable.
+    pub fn check_ptr_access_signed(
+        &self,
+        ptr: Pointer<Option<M::Provenance>>,
+        size: i64,
+        msg: CheckInAllocMsg,
+    ) -> InterpResult<'tcx> {
         self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| {
             let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
             Ok((size, align, ()))
@@ -416,7 +434,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
     /// to the allocation it points to. Supports both shared and mutable references, as the actual
-    /// checking is offloaded to a helper closure.
+    /// checking is offloaded to a helper closure. Supports signed sizes for checks "to the left" of
+    /// a pointer.
     ///
     /// `alloc_size` will only get called for non-zero-sized accesses.
     ///
@@ -424,7 +443,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     fn check_and_deref_ptr<T>(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
-        size: Size,
+        size: i64,
         msg: CheckInAllocMsg,
         alloc_size: impl FnOnce(
             AllocId,
@@ -433,25 +452,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         ) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
         // Everything is okay with size 0.
-        if size.bytes() == 0 {
+        if size == 0 {
             return Ok(None);
         }
 
-        Ok(match self.ptr_try_get_alloc_id(ptr) {
+        Ok(match self.ptr_try_get_alloc_id(ptr, size) {
             Err(addr) => {
                 // We couldn't get a proper allocation.
-                throw_ub!(DanglingIntPointer(addr, msg));
+                throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg });
             }
             Ok((alloc_id, offset, prov)) => {
                 let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
-                // Test bounds.
-                // It is sufficient to check this for the end pointer. Also check for overflow!
-                if offset.checked_add(size, &self.tcx).is_none_or(|end| end > alloc_size) {
+                let offset = offset.bytes();
+                // Compute absolute begin and end of the range.
+                let (begin, end) = if size >= 0 {
+                    (Some(offset), offset.checked_add(size as u64))
+                } else {
+                    (offset.checked_sub(size.unsigned_abs()), Some(offset))
+                };
+                // Ensure both are within bounds.
+                let in_bounds = begin.is_some() && end.is_some_and(|e| e <= alloc_size.bytes());
+                if !in_bounds {
                     throw_ub!(PointerOutOfBounds {
                         alloc_id,
                         alloc_size,
-                        ptr_offset: self.target_usize_to_isize(offset.bytes()),
-                        ptr_size: size,
+                        ptr_offset: self.sign_extend_to_target_isize(offset),
+                        inbounds_size: size,
                         msg,
                     })
                 }
@@ -482,7 +508,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
 
         #[inline]
-        fn offset_misalignment(offset: u64, align: Align) -> Option<Misalignment> {
+        fn is_offset_misaligned(offset: u64, align: Align) -> Option<Misalignment> {
             if offset % align.bytes() == 0 {
                 None
             } else {
@@ -492,8 +518,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
 
-        match self.ptr_try_get_alloc_id(ptr) {
-            Err(addr) => offset_misalignment(addr, align),
+        match self.ptr_try_get_alloc_id(ptr, 0) {
+            Err(addr) => is_offset_misaligned(addr, align),
             Ok((alloc_id, offset, _prov)) => {
                 let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id);
                 if let Some(misalign) =
@@ -501,14 +527,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 {
                     Some(misalign)
                 } else if M::Provenance::OFFSET_IS_ADDR {
-                    // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
-                    offset_misalignment(ptr.addr().bytes(), align)
+                    is_offset_misaligned(ptr.addr().bytes(), align)
                 } else {
                     // Check allocation alignment and offset alignment.
                     if alloc_align.bytes() < align.bytes() {
                         Some(Misalignment { has: alloc_align, required: align })
                     } else {
-                        offset_misalignment(offset.bytes(), align)
+                        is_offset_misaligned(offset.bytes(), align)
                     }
                 }
             }
@@ -644,9 +669,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: Size,
     ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
     {
+        let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
         let ptr_and_alloc = self.check_and_deref_ptr(
             ptr,
-            size,
+            size_i64,
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
                 let alloc = self.get_alloc_raw(alloc_id)?;
@@ -657,7 +683,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // accesses. That means we cannot rely on the closure above or the `Some` branch below. We
         // do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
         if !self.memory.validation_in_progress.get() {
-            if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr) {
+            if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
                 M::before_alloc_read(self, alloc_id)?;
             }
         }
@@ -878,7 +904,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         ptr: Pointer<Option<M::Provenance>>,
     ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
         trace!("get_ptr_fn({:?})", ptr);
-        let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
         if offset.bytes() != 0 {
             throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
         }
@@ -894,7 +920,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
     ) -> InterpResult<'tcx, Ty<'tcx>> {
         trace!("get_ptr_vtable({:?})", ptr);
-        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr, 0)?;
         if offset.bytes() != 0 {
             throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
         }
@@ -983,8 +1009,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         })
     }
 
-    /// Runs the close in "validation" mode, which means the machine's memory read hooks will be
+    /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be
     /// suppressed. Needless to say, this must only be set with great care! Cannot be nested.
+    ///
+    /// We do this so Miri's allocation access tracking does not show the validation
+    /// reads as spurious accesses.
     pub(super) fn run_for_validation<R>(&self, f: impl FnOnce() -> R) -> R {
         // This deliberately uses `==` on `bool` to follow the pattern
         // `assert!(val.replace(new) == old)`.
@@ -1375,7 +1404,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Err(_) => {
                 // Can only happen during CTFE.
                 let ptr = scalar.to_pointer(self)?;
-                match self.ptr_try_get_alloc_id(ptr) {
+                match self.ptr_try_get_alloc_id(ptr, 0) {
                     Ok((alloc_id, offset, _)) => {
                         let (size, _align, _kind) = self.get_alloc_info(alloc_id);
                         // If the pointer is out-of-bounds, it may be null.
@@ -1391,6 +1420,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Turning a "maybe pointer" into a proper pointer (and some information
     /// about where it points), or an absolute address.
     ///
+    /// `size` says how many bytes of memory are expected at that pointer. This is largely only used
+    /// for error messages; however, the *sign* of `size` can be used to disambiguate situations
+    /// where a wildcard pointer sits right in between two allocations.
+    /// It is almost always okay to just set the size to 0; this will be treated like a positive size
+    /// for handling wildcard pointers.
+    ///
     /// The result must be used immediately; it is not allowed to convert
     /// the returned data back into a `Pointer` and store that in machine state.
     /// (In fact that's not even possible since `M::ProvenanceExtra` is generic and
@@ -1398,9 +1433,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn ptr_try_get_alloc_id(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
+        size: i64,
     ) -> Result<(AllocId, Size, M::ProvenanceExtra), u64> {
         match ptr.into_pointer_or_addr() {
-            Ok(ptr) => match M::ptr_get_alloc(self, ptr) {
+            Ok(ptr) => match M::ptr_get_alloc(self, ptr, size) {
                 Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)),
                 None => {
                     assert!(M::Provenance::OFFSET_IS_ADDR);
@@ -1414,6 +1450,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     /// Turning a "maybe pointer" into a proper pointer (and some information about where it points).
     ///
+    /// `size` says how many bytes of memory are expected at that pointer. This is largely only used
+    /// for error messages; however, the *sign* of `size` can be used to disambiguate situations
+    /// where a wildcard pointer sits right in between two allocations.
+    /// It is almost always okay to just set the size to 0; this will be treated like a positive size
+    /// for handling wildcard pointers.
+    ///
     /// The result must be used immediately; it is not allowed to convert
     /// the returned data back into a `Pointer` and store that in machine state.
     /// (In fact that's not even possible since `M::ProvenanceExtra` is generic and
@@ -1422,9 +1464,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn ptr_get_alloc_id(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
+        size: i64,
     ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> {
-        self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
-            err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
+        self.ptr_try_get_alloc_id(ptr, size).map_err(|offset| {
+            err_ub!(DanglingIntPointer {
+                addr: offset,
+                inbounds_size: size,
+                msg: CheckInAllocMsg::InboundsTest
+            })
+            .into()
         })
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index f703c6fbe3e..511756e3f86 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -1,5 +1,6 @@
 //! An interpreter for MIR used in CTFE and by miri
 
+mod call;
 mod cast;
 mod discriminant;
 mod eval_context;
@@ -11,35 +12,32 @@ mod operand;
 mod operator;
 mod place;
 mod projection;
+mod stack;
 mod step;
-mod terminator;
 mod traits;
 mod util;
 mod validity;
 mod visitor;
 
+use eval_context::{from_known_layout, mir_assign_valid_types};
 #[doc(no_inline)]
 pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
 
-pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
+pub use self::call::FnArg;
+pub use self::eval_context::{format_interp_error, InterpCx};
 pub use self::intern::{
     intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
     InternResult,
 };
+pub(crate) use self::intrinsics::eval_nullary_intrinsic;
 pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, ReturnAction};
 pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
+use self::operand::Operand;
 pub use self::operand::{ImmTy, Immediate, OpTy, Readable};
 pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
+use self::place::{MemPlace, Place};
 pub use self::projection::{OffsetMode, Projectable};
-pub use self::terminator::FnArg;
+pub use self::stack::{Frame, FrameInfo, LocalState, StackPopCleanup, StackPopInfo};
+pub(crate) use self::util::create_static_alloc;
 pub use self::validity::{CtfeValidationMode, RefTracking};
 pub use self::visitor::ValueVisitor;
-
-use self::{
-    operand::Operand,
-    place::{MemPlace, Place},
-};
-
-pub(crate) use self::intrinsics::eval_nullary_intrinsic;
-pub(crate) use self::util::create_static_alloc;
-use eval_context::{from_known_layout, mir_assign_valid_types};
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 0a7e9853763..ad87d6953d3 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -4,16 +4,14 @@
 use std::assert_matches::assert_matches;
 
 use either::{Either, Left, Right};
-use tracing::trace;
-
 use rustc_hir::def::Namespace;
 use rustc_middle::mir::interpret::ScalarSizeMismatch;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
 use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
-use rustc_middle::{bug, span_bug};
-use rustc_middle::{mir, ty};
+use rustc_middle::{bug, mir, span_bug, ty};
 use rustc_target::abi::{self, Abi, HasDataLayout, Size};
+use tracing::trace;
 
 use super::{
     alloc_range, err_ub, from_known_layout, mir_assign_valid_types, throw_ub, CtfeProvenance,
@@ -186,6 +184,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     #[inline]
     pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
         debug_assert!(layout.abi.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout");
+        debug_assert_eq!(val.size(), layout.size);
         ImmTy { imm: val.into(), layout }
     }
 
@@ -343,7 +342,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
             }
             // extract fields from types with `ScalarPair` ABI
             (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
-                assert!(matches!(layout.abi, Abi::Scalar(..)));
+                assert_matches!(layout.abi, Abi::Scalar(..));
                 Immediate::from(if offset.bytes() == 0 {
                     debug_assert_eq!(layout.size, a.size(cx));
                     a_val
@@ -835,8 +834,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Immediate, 48);
     static_assert_size!(ImmTy<'_>, 64);
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 2723507397e..2f860f9f942 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -1,15 +1,14 @@
 use either::Either;
-
 use rustc_apfloat::{Float, FloatConvert};
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
+use rustc_middle::mir::NullOp;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, FloatTy, ScalarInt};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_span::symbol::sym;
 use tracing::trace;
 
-use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
+use super::{throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
@@ -300,17 +299,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Pointer ops that are always supported.
             Offset => {
                 let ptr = left.to_scalar().to_pointer(self)?;
-                let offset_count = right.to_scalar().to_target_isize(self)?;
                 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
+                let pointee_layout = self.layout_of(pointee_ty)?;
+                assert!(pointee_layout.abi.is_sized());
 
                 // We cannot overflow i64 as a type's size must be <= isize::MAX.
-                let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
-                // The computed offset, in bytes, must not overflow an isize.
-                // `checked_mul` enforces a too small bound, but no actual allocation can be big enough for
-                // the difference to be noticeable.
-                let offset_bytes =
-                    offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
+                let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
+                let pointee_size = ImmTy::from_int(pointee_size, right.layout);
+                // Multiply element size and element count.
+                let (val, overflowed) = self
+                    .binary_op(mir::BinOp::MulWithOverflow, right, &pointee_size)?
+                    .to_scalar_pair();
+                // This must not overflow.
+                if overflowed.to_bool()? {
+                    throw_ub!(PointerArithOverflow)
+                }
 
+                let offset_bytes = val.to_target_isize(self)?;
                 let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
                 Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout))
             }
@@ -331,11 +336,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         trace!(
             "Running binary op {:?}: {:?} ({}), {:?} ({})",
-            bin_op,
-            *left,
-            left.layout.ty,
-            *right,
-            right.layout.ty
+            bin_op, *left, left.layout.ty, *right, right.layout.ty
         );
 
         match left.layout.ty.kind() {
@@ -480,4 +481,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
     }
+
+    pub fn nullary_op(
+        &self,
+        null_op: NullOp<'tcx>,
+        arg_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
+        use rustc_middle::mir::NullOp::*;
+
+        let layout = self.layout_of(arg_ty)?;
+        let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap();
+
+        Ok(match null_op {
+            SizeOf => {
+                if !layout.abi.is_sized() {
+                    span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
+                }
+                let val = layout.size.bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            AlignOf => {
+                if !layout.abi.is_sized() {
+                    span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
+                }
+                let val = layout.align.abi.bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            OffsetOf(fields) => {
+                let val =
+                    self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            UbChecks => ImmTy::from_bool(self.tcx.sess.ub_checks(), *self.tcx),
+        })
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 33c25b746cc..2afdd02c880 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -5,20 +5,17 @@
 use std::assert_matches::assert_matches;
 
 use either::{Either, Left, Right};
-use tracing::{instrument, trace};
-
 use rustc_ast::Mutability;
-use rustc_middle::mir;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::Ty;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_target::abi::{Abi, Align, HasDataLayout, Size};
+use tracing::{instrument, trace};
 
 use super::{
-    alloc_range, mir_assign_valid_types, throw_ub, AllocRef, AllocRefMut, CheckAlignMsg,
-    CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment,
-    OffsetMode, OpTy, Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable,
-    Scalar,
+    alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance,
+    ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
+    Operand, Pointer, Projectable, Provenance, Readable, Scalar,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@@ -87,9 +84,6 @@ impl<Prov: Provenance> MemPlace<Prov> {
             !meta.has_meta() || self.meta.has_meta(),
             "cannot use `offset_with_meta` to add metadata to a place"
         );
-        if offset > ecx.data_layout().max_size_of_val() {
-            throw_ub!(PointerArithOverflow);
-        }
         let ptr = match mode {
             OffsetMode::Inbounds => {
                 ecx.ptr_offset_inbounds(self.ptr, offset.bytes().try_into().unwrap())?
@@ -291,10 +285,8 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
                 // projections are type-checked and bounds-checked.
                 assert!(offset + layout.size <= self.layout.size);
 
-                let new_offset = Size::from_bytes(
-                    ecx.data_layout()
-                        .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?,
-                );
+                // Size `+`, ensures no overflow.
+                let new_offset = old_offset.unwrap_or(Size::ZERO) + offset;
 
                 PlaceTy {
                     place: Place::Local { local, offset: Some(new_offset), locals_addr },
@@ -580,7 +572,10 @@ where
 
         if M::enforce_validity(self, dest.layout()) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(&dest.to_op(self)?)?;
+            self.validate_operand(
+                &dest.to_op(self)?,
+                M::enforce_validity_recursively(self, dest.layout()),
+            )?;
         }
 
         Ok(())
@@ -819,7 +814,10 @@ where
         // Generally for transmutation, data must be valid both at the old and new type.
         // But if the types are the same, the 2nd validation below suffices.
         if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) {
-            self.validate_operand(&src.to_op(self)?)?;
+            self.validate_operand(
+                &src.to_op(self)?,
+                M::enforce_validity_recursively(self, src.layout()),
+            )?;
         }
 
         // Do the actual copy.
@@ -827,7 +825,10 @@ where
 
         if validate_dest && M::enforce_validity(self, dest.layout()) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(&dest.to_op(self)?)?;
+            self.validate_operand(
+                &dest.to_op(self)?,
+                M::enforce_validity_recursively(self, dest.layout()),
+            )?;
         }
 
         Ok(())
@@ -1007,7 +1008,8 @@ where
         // 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());
+            let salt = M::get_global_alloc_salt(self, None);
+            let id = tcx.allocate_bytes_dedup(str.as_bytes(), salt);
 
             // 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))?
@@ -1034,8 +1036,9 @@ where
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(MemPlace, 48);
     static_assert_size!(MemPlaceMeta, 24);
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index cfa814c810a..dd8dd21e0e8 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -10,14 +10,10 @@
 use std::marker::PhantomData;
 use std::ops::Range;
 
-use rustc_middle::mir;
-use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::Ty;
-use rustc_middle::{bug, span_bug};
-use rustc_target::abi::Size;
-use rustc_target::abi::{self, VariantIdx};
-
+use rustc_middle::{bug, mir, span_bug, ty};
+use rustc_target::abi::{self, Size, VariantIdx};
 use tracing::{debug, instrument};
 
 use super::{
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
new file mode 100644
index 00000000000..50dbced6a2a
--- /dev/null
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -0,0 +1,651 @@
+//! Manages the low-level pushing and popping of stack frames and the (de)allocation of local variables.
+//! For hadling of argument passing and return values, see the `call` module.
+use std::cell::Cell;
+use std::{fmt, mem};
+
+use either::{Either, Left, Right};
+use rustc_hir as hir;
+use rustc_hir::definitions::DefPathData;
+use rustc_index::IndexVec;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, mir};
+use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_span::Span;
+use tracing::{info_span, instrument, trace};
+
+use super::{
+    from_known_layout, throw_ub, throw_unsup, AllocId, CtfeProvenance, Immediate, InterpCx,
+    InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, MemoryKind, Operand, Pointer,
+    Provenance, ReturnAction, Scalar,
+};
+use crate::errors;
+
+// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
+// boundary and dropped in the other thread, it would exit the span in the other thread.
+struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
+
+impl SpanGuard {
+    /// By default a `SpanGuard` does nothing.
+    fn new() -> Self {
+        Self(tracing::Span::none(), std::marker::PhantomData)
+    }
+
+    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
+    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
+    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
+    /// been pushed.
+    fn enter(&mut self, span: tracing::Span) {
+        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
+        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
+        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
+        // problems.
+        *self = Self(span, std::marker::PhantomData);
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.enter(id);
+        });
+    }
+}
+
+impl Drop for SpanGuard {
+    fn drop(&mut self) {
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.exit(id);
+        });
+    }
+}
+
+/// A stack frame.
+pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
+    ////////////////////////////////////////////////////////////////////////////////
+    // Function and callsite information
+    ////////////////////////////////////////////////////////////////////////////////
+    /// The MIR for the function called on this frame.
+    pub(super) body: &'tcx mir::Body<'tcx>,
+
+    /// The def_id and args of the current function.
+    pub(super) instance: ty::Instance<'tcx>,
+
+    /// Extra data for the machine.
+    pub extra: Extra,
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Return place and locals
+    ////////////////////////////////////////////////////////////////////////////////
+    /// Work to perform when returning from this function.
+    return_to_block: StackPopCleanup,
+
+    /// The location where the result of the current stack frame should be written to,
+    /// and its layout in the caller.
+    pub return_place: MPlaceTy<'tcx, Prov>,
+
+    /// The list of locals for this stack frame, stored in order as
+    /// `[return_ptr, arguments..., variables..., temporaries...]`.
+    /// The locals are stored as `Option<Value>`s.
+    /// `None` represents a local that is currently dead, while a live local
+    /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
+    ///
+    /// Do *not* access this directly; always go through the machine hook!
+    pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
+
+    /// The span of the `tracing` crate is stored here.
+    /// When the guard is dropped, the span is exited. This gives us
+    /// a full stack trace on all tracing statements.
+    tracing_span: SpanGuard,
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Current position within the function
+    ////////////////////////////////////////////////////////////////////////////////
+    /// If this is `Right`, we are not currently executing any particular statement in
+    /// this frame (can happen e.g. during frame initialization, and during unwinding on
+    /// frames without cleanup code).
+    ///
+    /// Needs to be public because ConstProp does unspeakable things to it.
+    pub(super) loc: Either<mir::Location, Span>,
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
+pub enum StackPopCleanup {
+    /// Jump to the next block in the caller, or cause UB if None (that's a function
+    /// that may never return). Also store layout of return place so
+    /// we can validate it at that layout.
+    /// `ret` stores the block we jump to on a normal return, while `unwind`
+    /// stores the block used for cleanup during unwinding.
+    Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
+    /// The root frame of the stack: nowhere else to jump to.
+    /// `cleanup` says whether locals are deallocated. Static computation
+    /// wants them leaked to intern what they need (and just throw away
+    /// the entire `ecx` when it is done).
+    Root { cleanup: bool },
+}
+
+/// Return type of [`InterpCx::pop_stack_frame_raw`].
+pub struct StackPopInfo<'tcx, Prov: Provenance> {
+    /// Additional information about the action to be performed when returning from the popped
+    /// stack frame.
+    pub return_action: ReturnAction,
+
+    /// [`return_to_block`](Frame::return_to_block) of the popped stack frame.
+    pub return_to_block: StackPopCleanup,
+
+    /// [`return_place`](Frame::return_place) of the popped stack frame.
+    pub return_place: MPlaceTy<'tcx, Prov>,
+}
+
+/// State of a local variable including a memoized layout
+#[derive(Clone)]
+pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
+    value: LocalValue<Prov>,
+    /// Don't modify if `Some`, this is only used to prevent computing the layout twice.
+    /// Avoids computing the layout of locals that are never actually initialized.
+    layout: Cell<Option<TyAndLayout<'tcx>>>,
+}
+
+impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("LocalState")
+            .field("value", &self.value)
+            .field("ty", &self.layout.get().map(|l| l.ty))
+            .finish()
+    }
+}
+
+/// Current value of a local variable
+///
+/// This does not store the type of the local; the type is given by `body.local_decls` and can never
+/// change, so by not storing here we avoid having to maintain that as an invariant.
+#[derive(Copy, Clone, Debug)] // Miri debug-prints these
+pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
+    /// This local is not currently alive, and cannot be used at all.
+    Dead,
+    /// A normal, live local.
+    /// Mostly for convenience, we re-use the `Operand` type here.
+    /// This is an optimization over just always having a pointer here;
+    /// we can thus avoid doing an allocation when the local just stores
+    /// immediate values *and* never has its address taken.
+    Live(Operand<Prov>),
+}
+
+impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
+    pub fn make_live_uninit(&mut self) {
+        self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
+    }
+
+    /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState`
+    /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type
+    /// private.
+    pub fn as_mplace_or_imm(
+        &self,
+    ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> {
+        match self.value {
+            LocalValue::Dead => None,
+            LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))),
+            LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)),
+        }
+    }
+
+    /// Read the local's value or error if the local is not yet live or not live anymore.
+    #[inline(always)]
+    pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
+        match &self.value {
+            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
+            LocalValue::Live(val) => Ok(val),
+        }
+    }
+
+    /// Overwrite the local. If the local can be overwritten in place, return a reference
+    /// to do so; otherwise return the `MemPlace` to consult instead.
+    #[inline(always)]
+    pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
+        match &mut self.value {
+            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
+            LocalValue::Live(val) => Ok(val),
+        }
+    }
+}
+
+/// What we store about a frame in an interpreter backtrace.
+#[derive(Clone, Debug)]
+pub struct FrameInfo<'tcx> {
+    pub instance: ty::Instance<'tcx>,
+    pub span: Span,
+}
+
+// FIXME: only used by miri, should be removed once translatable.
+impl<'tcx> fmt::Display for FrameInfo<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        ty::tls::with(|tcx| {
+            if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
+                write!(f, "inside closure")
+            } else {
+                // Note: this triggers a `must_produce_diag` state, which means that if we ever
+                // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
+                // we actually want to emit a warning or error to the user.
+                write!(f, "inside `{}`", self.instance)
+            }
+        })
+    }
+}
+
+impl<'tcx> FrameInfo<'tcx> {
+    pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote {
+        let span = self.span;
+        if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
+            errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 }
+        } else {
+            let instance = format!("{}", self.instance);
+            // Note: this triggers a `must_produce_diag` state, which means that if we ever get
+            // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
+            // actually want to emit a warning or error to the user.
+            errors::FrameNote { where_: "instance", span, instance, times: 0 }
+        }
+    }
+}
+
+impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
+    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'tcx, Prov, Extra> {
+        Frame {
+            body: self.body,
+            instance: self.instance,
+            return_to_block: self.return_to_block,
+            return_place: self.return_place,
+            locals: self.locals,
+            loc: self.loc,
+            extra,
+            tracing_span: self.tracing_span,
+        }
+    }
+}
+
+impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
+    /// Get the current location within the Frame.
+    ///
+    /// If this is `Right`, we are not currently executing any particular statement in
+    /// this frame (can happen e.g. during frame initialization, and during unwinding on
+    /// frames without cleanup code).
+    ///
+    /// Used by [priroda](https://github.com/oli-obk/priroda).
+    pub fn current_loc(&self) -> Either<mir::Location, Span> {
+        self.loc
+    }
+
+    pub fn body(&self) -> &'tcx mir::Body<'tcx> {
+        self.body
+    }
+
+    pub fn instance(&self) -> ty::Instance<'tcx> {
+        self.instance
+    }
+
+    /// Return the `SourceInfo` of the current instruction.
+    pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
+        self.loc.left().map(|loc| self.body.source_info(loc))
+    }
+
+    pub fn current_span(&self) -> Span {
+        match self.loc {
+            Left(loc) => self.body.source_info(loc).span,
+            Right(span) => span,
+        }
+    }
+
+    pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
+        // We first try to get a HirId via the current source scope,
+        // and fall back to `body.source`.
+        self.current_source_info()
+            .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
+                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+                mir::ClearCrossCrate::Clear => None,
+            })
+            .or_else(|| {
+                let def_id = self.body.source.def_id().as_local();
+                def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
+            })
+    }
+
+    /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
+    /// sanity check to detect bugs where we mix up which stack frame a place refers to.
+    #[inline(always)]
+    pub(super) fn locals_addr(&self) -> usize {
+        self.locals.raw.as_ptr().addr()
+    }
+
+    #[must_use]
+    pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec<FrameInfo<'tcx>> {
+        let mut frames = Vec::new();
+        // This deliberately does *not* honor `requires_caller_location` since it is used for much
+        // more than just panics.
+        for frame in stack.iter().rev() {
+            let span = match frame.loc {
+                Left(loc) => {
+                    // If the stacktrace passes through MIR-inlined source scopes, add them.
+                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
+                    let mut scope_data = &frame.body.source_scopes[scope];
+                    while let Some((instance, call_span)) = scope_data.inlined {
+                        frames.push(FrameInfo { span, instance });
+                        span = call_span;
+                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
+                    }
+                    span
+                }
+                Right(span) => span,
+            };
+            frames.push(FrameInfo { span, instance: frame.instance });
+        }
+        trace!("generate stacktrace: {:#?}", frames);
+        frames
+    }
+}
+
+impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
+    /// Very low-level helper that pushes a stack frame without initializing
+    /// the arguments or local variables.
+    ///
+    /// The high-level version of this is `init_stack_frame`.
+    #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
+    pub(crate) fn push_stack_frame_raw(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+        body: &'tcx mir::Body<'tcx>,
+        return_place: &MPlaceTy<'tcx, M::Provenance>,
+        return_to_block: StackPopCleanup,
+    ) -> InterpResult<'tcx> {
+        trace!("body: {:#?}", body);
+
+        // We can push a `Root` frame if and only if the stack is empty.
+        debug_assert_eq!(
+            self.stack().is_empty(),
+            matches!(return_to_block, StackPopCleanup::Root { .. })
+        );
+
+        // First push a stack frame so we have access to `instantiate_from_current_frame` and other
+        // `self.frame()`-based functions.
+        let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
+        let locals = IndexVec::from_elem(dead_local, &body.local_decls);
+        let pre_frame = Frame {
+            body,
+            loc: Right(body.span), // Span used for errors caused during preamble.
+            return_to_block,
+            return_place: return_place.clone(),
+            locals,
+            instance,
+            tracing_span: SpanGuard::new(),
+            extra: (),
+        };
+        let frame = M::init_frame(self, pre_frame)?;
+        self.stack_mut().push(frame);
+
+        // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
+        for &const_ in body.required_consts() {
+            let c =
+                self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
+            c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
+                err.emit_note(*self.tcx);
+                err
+            })?;
+        }
+
+        // Finish things up.
+        M::after_stack_push(self)?;
+        self.frame_mut().loc = Left(mir::Location::START);
+        let span = info_span!("frame", "{}", instance);
+        self.frame_mut().tracing_span.enter(span);
+
+        Ok(())
+    }
+
+    /// Low-level helper that pops a stack frame from the stack and returns some information about
+    /// it.
+    ///
+    /// This also deallocates locals, if necessary.
+    ///
+    /// [`M::before_stack_pop`] should be called before calling this function.
+    /// [`M::after_stack_pop`] is called by this function automatically.
+    ///
+    /// The high-level version of this is `return_from_current_stack_frame`.
+    ///
+    /// [`M::before_stack_pop`]: Machine::before_stack_pop
+    /// [`M::after_stack_pop`]: Machine::after_stack_pop
+    pub(super) fn pop_stack_frame_raw(
+        &mut self,
+        unwinding: bool,
+    ) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
+        let cleanup = self.cleanup_current_frame_locals()?;
+
+        let frame =
+            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
+
+        let return_to_block = frame.return_to_block;
+        let return_place = frame.return_place.clone();
+
+        let return_action;
+        if cleanup {
+            return_action = M::after_stack_pop(self, frame, unwinding)?;
+            assert_ne!(return_action, ReturnAction::NoCleanup);
+        } else {
+            return_action = ReturnAction::NoCleanup;
+        };
+
+        Ok(StackPopInfo { return_action, return_to_block, return_place })
+    }
+
+    /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw).
+    /// Returns `true` if cleanup has been done, `false` otherwise.
+    fn cleanup_current_frame_locals(&mut self) -> InterpResult<'tcx, bool> {
+        // Cleanup: deallocate locals.
+        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
+        // We do this while the frame is still on the stack, so errors point to the callee.
+        let return_to_block = self.frame().return_to_block;
+        let cleanup = match return_to_block {
+            StackPopCleanup::Goto { .. } => true,
+            StackPopCleanup::Root { cleanup, .. } => cleanup,
+        };
+
+        if cleanup {
+            // We need to take the locals out, since we need to mutate while iterating.
+            let locals = mem::take(&mut self.frame_mut().locals);
+            for local in &locals {
+                self.deallocate_local(local.value)?;
+            }
+        }
+
+        Ok(cleanup)
+    }
+
+    /// In the current stack frame, mark all locals as live that are not arguments and don't have
+    /// `Storage*` annotations (this includes the return place).
+    pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> {
+        self.storage_live(mir::RETURN_PLACE)?;
+
+        let body = self.body();
+        let always_live = always_storage_live_locals(body);
+        for local in body.vars_and_temps_iter() {
+            if always_live.contains(local) {
+                self.storage_live(local)?;
+            }
+        }
+        Ok(())
+    }
+
+    pub fn storage_live_dyn(
+        &mut self,
+        local: mir::Local,
+        meta: MemPlaceMeta<M::Provenance>,
+    ) -> InterpResult<'tcx> {
+        trace!("{:?} is now live", local);
+
+        // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs.
+        fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
+            match ty.kind() {
+                ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+                | ty::Uint(_)
+                | ty::Int(_)
+                | ty::Bool
+                | ty::Float(_)
+                | ty::FnDef(..)
+                | ty::FnPtr(_)
+                | ty::RawPtr(..)
+                | ty::Char
+                | ty::Ref(..)
+                | ty::Coroutine(..)
+                | ty::CoroutineWitness(..)
+                | ty::Array(..)
+                | ty::Closure(..)
+                | ty::CoroutineClosure(..)
+                | ty::Never
+                | ty::Error(_)
+                | ty::Dynamic(_, _, ty::DynStar) => true,
+
+                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
+
+                ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
+
+                ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
+
+                // We don't want to do any queries, so there is not much we can do with ADTs.
+                ty::Adt(..) => false,
+
+                ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
+
+                ty::Infer(ty::TyVar(_)) => false,
+
+                ty::Bound(..)
+                | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                    bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
+                }
+            }
+        }
+
+        // This is a hot function, we avoid computing the layout when possible.
+        // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types.
+        let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) {
+            None
+        } else {
+            // We need the layout.
+            let layout = self.layout_of_local(self.frame(), local, None)?;
+            if layout.is_sized() { None } else { Some(layout) }
+        };
+
+        let local_val = LocalValue::Live(if let Some(layout) = unsized_ {
+            if !meta.has_meta() {
+                throw_unsup!(UnsizedLocal);
+            }
+            // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized.
+            let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
+            Operand::Indirect(*dest_place.mplace())
+        } else {
+            assert!(!meta.has_meta()); // we're dropping the metadata
+            // Just make this an efficient immediate.
+            // Note that not calling `layout_of` here does have one real consequence:
+            // if the type is too big, we'll only notice this when the local is actually initialized,
+            // which is a bit too late -- we should ideally notice this already here, when the memory
+            // is conceptually allocated. But given how rare that error is and that this is a hot function,
+            // we accept this downside for now.
+            Operand::Immediate(Immediate::Uninit)
+        });
+
+        // If the local is already live, deallocate its old memory.
+        let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
+        self.deallocate_local(old)?;
+        Ok(())
+    }
+
+    /// Mark a storage as live, killing the previous content.
+    #[inline(always)]
+    pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
+        self.storage_live_dyn(local, MemPlaceMeta::None)
+    }
+
+    pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
+        assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
+        trace!("{:?} is now dead", local);
+
+        // If the local is already dead, this is a NOP.
+        let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
+        self.deallocate_local(old)?;
+        Ok(())
+    }
+
+    fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
+        if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
+            // All locals have a backing allocation, even if the allocation is empty
+            // due to the local having ZST type. Hence we can `unwrap`.
+            trace!(
+                "deallocating local {:?}: {:?}",
+                local,
+                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
+                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
+            );
+            self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
+        };
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(super) fn layout_of_local(
+        &self,
+        frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
+        local: mir::Local,
+        layout: Option<TyAndLayout<'tcx>>,
+    ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
+        let state = &frame.locals[local];
+        if let Some(layout) = state.layout.get() {
+            return Ok(layout);
+        }
+
+        let layout = from_known_layout(self.tcx, self.param_env, layout, || {
+            let local_ty = frame.body.local_decls[local].ty;
+            let local_ty =
+                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+            self.layout_of(local_ty)
+        })?;
+
+        // Layouts of locals are requested a lot, so we cache them.
+        state.layout.set(Some(layout));
+        Ok(layout)
+    }
+}
+
+impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
+    pub(super) fn print(
+        &self,
+        allocs: &mut Vec<Option<AllocId>>,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        match self.value {
+            LocalValue::Dead => write!(fmt, " is dead")?,
+            LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
+                write!(fmt, " is uninitialized")?
+            }
+            LocalValue::Live(Operand::Indirect(mplace)) => {
+                write!(
+                    fmt,
+                    " by {} ref {:?}:",
+                    match mplace.meta {
+                        MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"),
+                        MemPlaceMeta::None => String::new(),
+                    },
+                    mplace.ptr,
+                )?;
+                allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
+            }
+            LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
+                write!(fmt, " {val:?}")?;
+                if let Scalar::Ptr(ptr, _size) = val {
+                    allocs.push(ptr.provenance.get_alloc_id());
+                }
+            }
+            LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
+                write!(fmt, " ({val1:?}, {val2:?})")?;
+                if let Scalar::Ptr(ptr, _size) = val1 {
+                    allocs.push(ptr.provenance.get_alloc_id());
+                }
+                if let Scalar::Ptr(ptr, _size) = val2 {
+                    allocs.push(ptr.provenance.get_alloc_id());
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index b3124dfdfbc..2527eca3446 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -3,19 +3,30 @@
 //! The main entry point is the `step` method.
 
 use either::Either;
-use tracing::{info, instrument, trace};
-
 use rustc_index::IndexSlice;
-use rustc_middle::mir;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::ty::layout::FnAbiOf;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::{bug, mir, span_bug};
+use rustc_span::source_map::Spanned;
+use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
+use tracing::{info, instrument, trace};
 
 use super::{
-    ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, Projectable, Scalar,
+    throw_ub, FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta,
+    PlaceTy, Projectable, Scalar,
 };
 use crate::util;
 
+struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> {
+    callee: FnVal<'tcx, M::ExtraFnVal>,
+    args: Vec<FnArg<'tcx, M::Provenance>>,
+    fn_sig: ty::FnSig<'tcx>,
+    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
+    /// True if the function is marked as `#[track_caller]` ([`ty::InstanceKind::requires_caller_location`])
+    with_caller_location: bool,
+}
+
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Returns `true` as long as there are more things to do.
     ///
@@ -39,7 +50,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
             let old_frames = self.frame_idx();
-            self.statement(stmt)?;
+            self.eval_statement(stmt)?;
             // Make sure we are not updating `statement_index` of the wrong frame.
             assert_eq!(old_frames, self.frame_idx());
             // Advance the program counter.
@@ -50,7 +61,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         M::before_terminator(self)?;
 
         let terminator = basic_block.terminator();
-        self.terminator(terminator)?;
+        self.eval_terminator(terminator)?;
+        if !self.stack().is_empty() {
+            if let Either::Left(loc) = self.frame().loc {
+                info!("// executing {:?}", loc.block);
+            }
+        }
         Ok(true)
     }
 
@@ -58,7 +74,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// statement counter.
     ///
     /// This does NOT move the statement counter forward, the caller has to do that!
-    pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
+    pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
 
         use rustc_middle::mir::StatementKind::*;
@@ -96,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 M::retag_place_contents(self, *kind, &dest)?;
             }
 
-            Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
+            Intrinsic(box intrinsic) => self.eval_nondiverging_intrinsic(intrinsic)?,
 
             // Evaluate the place expression, without reading from it.
             PlaceMention(box place) => {
@@ -181,6 +197,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_immediate(*result, &dest)?;
             }
 
+            NullaryOp(null_op, ty) => {
+                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
+                let val = self.nullary_op(null_op, ty)?;
+                self.write_immediate(*val, &dest)?;
+            }
+
             Aggregate(box ref kind, ref operands) => {
                 self.write_aggregate(kind, operands, &dest)?;
             }
@@ -232,38 +254,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_immediate(*val, &dest)?;
             }
 
-            NullaryOp(ref null_op, ty) => {
-                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
-                let layout = self.layout_of(ty)?;
-                if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
-                    && layout.is_unsized()
-                {
-                    span_bug!(
-                        self.frame().current_span(),
-                        "{null_op:?} MIR operator called for unsized type {ty}",
-                    );
-                }
-                let val = match null_op {
-                    mir::NullOp::SizeOf => {
-                        let val = layout.size.bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::AlignOf => {
-                        let val = layout.align.abi.bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::OffsetOf(fields) => {
-                        let val = self
-                            .tcx
-                            .offset_of_subfield(self.param_env, layout, fields.iter())
-                            .bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()),
-                };
-                self.write_scalar(val, &dest)?;
-            }
-
             ShallowInitBox(ref operand, _) => {
                 let src = self.eval_operand(operand, None)?;
                 let v = self.read_immediate(&src)?;
@@ -364,7 +354,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // of the first element.
             let elem_size = first.layout.size;
             let first_ptr = first.ptr();
-            let rest_ptr = first_ptr.offset(elem_size, self)?;
+            let rest_ptr = first_ptr.wrapping_offset(elem_size, self);
             // No alignment requirement since `copy_op` above already checked it.
             self.mem_copy_repeatedly(
                 first_ptr,
@@ -378,16 +368,222 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
-    /// Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly.
-    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
+    /// Evaluate the arguments of a function call
+    fn eval_fn_call_argument(
+        &self,
+        op: &mir::Operand<'tcx>,
+    ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
+        Ok(match op {
+            mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
+                // Make a regular copy.
+                let op = self.eval_operand(op, None)?;
+                FnArg::Copy(op)
+            }
+            mir::Operand::Move(place) => {
+                // If this place lives in memory, preserve its location.
+                // We call `place_to_op` which will be an `MPlaceTy` whenever there exists
+                // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
+                // which can return a local even if that has an mplace.)
+                let place = self.eval_place(*place)?;
+                let op = self.place_to_op(&place)?;
+
+                match op.as_mplace_or_imm() {
+                    Either::Left(mplace) => FnArg::InPlace(mplace),
+                    Either::Right(_imm) => {
+                        // This argument doesn't live in memory, so there's no place
+                        // to make inaccessible during the call.
+                        // We rely on there not being any stray `PlaceTy` that would let the
+                        // caller directly access this local!
+                        // This is also crucial for tail calls, where we want the `FnArg` to
+                        // stay valid when the old stack frame gets popped.
+                        FnArg::Copy(op)
+                    }
+                }
+            }
+        })
+    }
+
+    /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
+    /// necessary information about callee and arguments to make a call.
+    fn eval_callee_and_args(
+        &self,
+        terminator: &mir::Terminator<'tcx>,
+        func: &mir::Operand<'tcx>,
+        args: &[Spanned<mir::Operand<'tcx>>],
+    ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
+        let func = self.eval_operand(func, None)?;
+        let args = args
+            .iter()
+            .map(|arg| self.eval_fn_call_argument(&arg.node))
+            .collect::<InterpResult<'tcx, Vec<_>>>()?;
+
+        let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
+        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
+        let extra_args = &args[fn_sig.inputs().len()..];
+        let extra_args =
+            self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
+
+        let (callee, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
+            ty::FnPtr(_sig) => {
+                let fn_ptr = self.read_pointer(&func)?;
+                let fn_val = self.get_ptr_fn(fn_ptr)?;
+                (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
+            }
+            ty::FnDef(def_id, args) => {
+                let instance = self.resolve(def_id, args)?;
+                (
+                    FnVal::Instance(instance),
+                    self.fn_abi_of_instance(instance, extra_args)?,
+                    instance.def.requires_caller_location(*self.tcx),
+                )
+            }
+            _ => {
+                span_bug!(terminator.source_info.span, "invalid callee of type {}", func.layout.ty)
+            }
+        };
+
+        Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
+    }
+
+    fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", terminator.kind);
 
-        self.eval_terminator(terminator)?;
-        if !self.stack().is_empty() {
-            if let Either::Left(loc) = self.frame().loc {
-                info!("// executing {:?}", loc.block);
+        use rustc_middle::mir::TerminatorKind::*;
+        match terminator.kind {
+            Return => {
+                self.return_from_current_stack_frame(/* unwinding */ false)?
+            }
+
+            Goto { target } => self.go_to_block(target),
+
+            SwitchInt { ref discr, ref targets } => {
+                let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
+                trace!("SwitchInt({:?})", *discr);
+
+                // Branch to the `otherwise` case by default, if no match is found.
+                let mut target_block = targets.otherwise();
+
+                for (const_int, target) in targets.iter() {
+                    // Compare using MIR BinOp::Eq, to also support pointer values.
+                    // (Avoiding `self.binary_op` as that does some redundant layout computation.)
+                    let res = self.binary_op(
+                        mir::BinOp::Eq,
+                        &discr,
+                        &ImmTy::from_uint(const_int, discr.layout),
+                    )?;
+                    if res.to_scalar().to_bool()? {
+                        target_block = target;
+                        break;
+                    }
+                }
+
+                self.go_to_block(target_block);
+            }
+
+            Call {
+                ref func,
+                ref args,
+                destination,
+                target,
+                unwind,
+                call_source: _,
+                fn_span: _,
+            } => {
+                let old_stack = self.frame_idx();
+                let old_loc = self.frame().loc;
+
+                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
+                    self.eval_callee_and_args(terminator, func, args)?;
+
+                let destination = self.force_allocation(&self.eval_place(destination)?)?;
+                self.init_fn_call(
+                    callee,
+                    (fn_sig.abi, fn_abi),
+                    &args,
+                    with_caller_location,
+                    &destination,
+                    target,
+                    if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
+                )?;
+                // Sanity-check that `eval_fn_call` either pushed a new frame or
+                // did a jump to another block.
+                if self.frame_idx() == old_stack && self.frame().loc == old_loc {
+                    span_bug!(terminator.source_info.span, "evaluating this call made no progress");
+                }
+            }
+
+            TailCall { ref func, ref args, fn_span: _ } => {
+                let old_frame_idx = self.frame_idx();
+
+                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
+                    self.eval_callee_and_args(terminator, func, args)?;
+
+                self.init_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
+
+                if self.frame_idx() != old_frame_idx {
+                    span_bug!(
+                        terminator.source_info.span,
+                        "evaluating this tail call pushed a new stack frame"
+                    );
+                }
+            }
+
+            Drop { place, target, unwind, replace: _ } => {
+                let place = self.eval_place(place)?;
+                let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
+                if let ty::InstanceKind::DropGlue(_, None) = instance.def {
+                    // This is the branch we enter if and only if the dropped type has no drop glue
+                    // whatsoever. This can happen as a result of monomorphizing a drop of a
+                    // generic. In order to make sure that generic and non-generic code behaves
+                    // roughly the same (and in keeping with Mir semantics) we do nothing here.
+                    self.go_to_block(target);
+                    return Ok(());
+                }
+                trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty);
+                self.init_drop_in_place_call(&place, instance, target, unwind)?;
+            }
+
+            Assert { ref cond, expected, ref msg, target, unwind } => {
+                let ignored =
+                    M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
+                let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
+                if ignored || expected == cond_val {
+                    self.go_to_block(target);
+                } else {
+                    M::assert_panic(self, msg, unwind)?;
+                }
+            }
+
+            UnwindTerminate(reason) => {
+                M::unwind_terminate(self, reason)?;
+            }
+
+            // When we encounter Resume, we've finished unwinding
+            // cleanup for the current stack frame. We pop it in order
+            // to continue unwinding the next frame
+            UnwindResume => {
+                trace!("unwinding: resuming from cleanup");
+                // By definition, a Resume terminator means
+                // that we're unwinding
+                self.return_from_current_stack_frame(/* unwinding */ true)?;
+                return Ok(());
+            }
+
+            // It is UB to ever encounter this.
+            Unreachable => throw_ub!(Unreachable),
+
+            // These should never occur for MIR we actually run.
+            FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | CoroutineDrop => span_bug!(
+                terminator.source_info.span,
+                "{:#?} should have been eliminated by MIR pass",
+                terminator.kind
+            ),
+
+            InlineAsm { template, ref operands, options, ref targets, .. } => {
+                M::eval_inline_asm(self, template, operands, options, targets)?;
             }
         }
+
         Ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index fb50661b826..cd4faf06655 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -28,7 +28,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         ensure_monomorphic_enough(*self.tcx, ty)?;
         ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
 
-        let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref);
+        let salt = M::get_global_alloc_salt(self, None);
+        let vtable_symbolic_allocation =
+            self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref, salt);
         let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
         Ok(vtable_ptr.into())
     }
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index bbe5e5fe3ed..6f5bcebbbb6 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,4 +1,5 @@
-use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
+use std::ops::ControlFlow;
+
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
@@ -6,10 +7,10 @@ use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
-use std::ops::ControlFlow;
 use tracing::debug;
 
 use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
+use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
 
 /// Checks whether a type contains generic parameters which must be instantiated.
 ///
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 3dc3e6c8833..fadc4ee6c8a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -9,17 +9,15 @@ use std::hash::Hash;
 use std::num::NonZero;
 
 use either::{Left, Right};
-use tracing::trace;
-
 use hir::def::DefKind;
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_middle::bug;
+use rustc_middle::mir::interpret::ValidationErrorKind::{self, *};
 use rustc_middle::mir::interpret::{
     ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
     UnsupportedOpInfo, ValidationErrorInfo,
-    ValidationErrorKind::{self, *},
 };
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
@@ -27,11 +25,13 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::{
     Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
 };
+use tracing::trace;
 
+use super::machine::AllocMap;
 use super::{
-    err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, AllocKind, CheckInAllocMsg,
-    GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
-    Pointer, Projectable, Scalar, ValueVisitor,
+    err_ub, format_interp_error, throw_ub, AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy,
+    Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable,
+    Scalar, ValueVisitor,
 };
 
 // for the validation errors
@@ -155,8 +155,8 @@ impl CtfeValidationMode {
 
 /// State for tracking recursive validation of references
 pub struct RefTracking<T, PATH = ()> {
-    pub seen: FxHashSet<T>,
-    pub todo: Vec<(T, PATH)>,
+    seen: FxHashSet<T>,
+    todo: Vec<(T, PATH)>,
 }
 
 impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
@@ -169,8 +169,11 @@ impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH>
         ref_tracking_for_consts.seen.insert(op);
         ref_tracking_for_consts
     }
+    pub fn next(&mut self) -> Option<(T, PATH)> {
+        self.todo.pop()
+    }
 
-    pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
+    fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
         if self.seen.insert(op.clone()) {
             trace!("Recursing below ptr {:#?}", op);
             let path = path();
@@ -340,7 +343,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         meta: MemPlaceMeta<M::Provenance>,
         pointee: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx> {
-        let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
+        let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env);
         match tail.kind() {
             ty::Dynamic(data, _, ty::Dyn) => {
                 let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
@@ -348,7 +351,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 try_validation!(
                     self.ecx.get_ptr_vtable_ty(vtable, Some(data)),
                     self.path,
-                    Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
+                    Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) =>
                         InvalidVTablePtr { value: format!("{vtable}") },
                     Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
                         InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
@@ -405,8 +408,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
-            Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind },
-            Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance {
+            Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },
+            Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
                 ptr_kind,
                 // FIXME this says "null pointer" when null but we need translate
                 pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(*i))
@@ -435,88 +438,96 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
             throw_validation_failure!(self.path, NullPtr { ptr_kind })
         }
-        // Do not allow pointers to uninhabited types.
+        // Do not allow references to uninhabited types.
         if place.layout.abi.is_uninhabited() {
             let ty = place.layout.ty;
             throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty })
         }
         // Recursive checking
         if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() {
-            // Determine whether this pointer expects to be pointing to something mutable.
-            let ptr_expected_mutbl = match ptr_kind {
-                PointerKind::Box => Mutability::Mut,
-                PointerKind::Ref(mutbl) => {
-                    // We do not take into account interior mutability here since we cannot know if
-                    // there really is an `UnsafeCell` inside `Option<UnsafeCell>` -- so we check
-                    // that in the recursive descent behind this reference (controlled by
-                    // `allow_immutable_unsafe_cell`).
-                    mutbl
-                }
-            };
             // Proceed recursively even for ZST, no reason to skip them!
             // `!` is a ZST and we want to validate it.
-            if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
+            if let Some(ctfe_mode) = self.ctfe_mode {
                 let mut skip_recursive_check = false;
-                if let Some(GlobalAlloc::Static(did)) = self.ecx.tcx.try_get_global_alloc(alloc_id)
+                // CTFE imposes restrictions on what references can point to.
+                if let Ok((alloc_id, _offset, _prov)) =
+                    self.ecx.ptr_try_get_alloc_id(place.ptr(), 0)
                 {
-                    let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() };
-                    // Special handling for pointers to statics (irrespective of their type).
-                    assert!(!self.ecx.tcx.is_thread_local_static(did));
-                    assert!(self.ecx.tcx.is_static(did));
-                    // Mode-specific checks
-                    match self.ctfe_mode {
-                        Some(
-                            CtfeValidationMode::Static { .. } | CtfeValidationMode::Promoted { .. },
-                        ) => {
-                            // We skip recursively checking other statics. These statics must be sound by
-                            // themselves, and the only way to get broken statics here is by using
-                            // unsafe code.
-                            // The reasons we don't check other statics is twofold. For one, in all
-                            // sound cases, the static was already validated on its own, and second, we
-                            // trigger cycle errors if we try to compute the value of the other static
-                            // and that static refers back to us (potentially through a promoted).
-                            // This could miss some UB, but that's fine.
-                            // We still walk nested allocations, as they are fundamentally part of this validation run.
-                            // This means we will also recurse into nested statics of *other*
-                            // statics, even though we do not recurse into other statics directly.
-                            // That's somewhat inconsistent but harmless.
-                            skip_recursive_check = !nested;
-                        }
-                        Some(CtfeValidationMode::Const { .. }) => {
-                            // We can't recursively validate `extern static`, so we better reject them.
-                            if self.ecx.tcx.is_foreign_item(did) {
-                                throw_validation_failure!(self.path, ConstRefToExtern);
+                    if let Some(GlobalAlloc::Static(did)) =
+                        self.ecx.tcx.try_get_global_alloc(alloc_id)
+                    {
+                        let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
+                            bug!()
+                        };
+                        // Special handling for pointers to statics (irrespective of their type).
+                        assert!(!self.ecx.tcx.is_thread_local_static(did));
+                        assert!(self.ecx.tcx.is_static(did));
+                        // Mode-specific checks
+                        match ctfe_mode {
+                            CtfeValidationMode::Static { .. }
+                            | CtfeValidationMode::Promoted { .. } => {
+                                // We skip recursively checking other statics. These statics must be sound by
+                                // themselves, and the only way to get broken statics here is by using
+                                // unsafe code.
+                                // The reasons we don't check other statics is twofold. For one, in all
+                                // sound cases, the static was already validated on its own, and second, we
+                                // trigger cycle errors if we try to compute the value of the other static
+                                // and that static refers back to us (potentially through a promoted).
+                                // This could miss some UB, but that's fine.
+                                // We still walk nested allocations, as they are fundamentally part of this validation run.
+                                // This means we will also recurse into nested statics of *other*
+                                // statics, even though we do not recurse into other statics directly.
+                                // That's somewhat inconsistent but harmless.
+                                skip_recursive_check = !nested;
+                            }
+                            CtfeValidationMode::Const { .. } => {
+                                // We can't recursively validate `extern static`, so we better reject them.
+                                if self.ecx.tcx.is_foreign_item(did) {
+                                    throw_validation_failure!(self.path, ConstRefToExtern);
+                                }
                             }
                         }
-                        None => {}
                     }
-                }
 
-                // Dangling and Mutability check.
-                let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id);
-                if alloc_kind == AllocKind::Dead {
-                    // This can happen for zero-sized references. We can't have *any* references to non-existing
-                    // allocations though, interning rejects them all as the rest of rustc isn't happy with them...
-                    // so we throw an error, even though this isn't really UB.
-                    // A potential future alternative would be to resurrect this as a zero-sized allocation
-                    // (which codegen will then compile to an aligned dummy pointer anyway).
-                    throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
-                }
-                // If this allocation has size zero, there is no actual mutability here.
-                if size != Size::ZERO {
-                    let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
-                    // Mutable pointer to immutable memory is no good.
-                    if ptr_expected_mutbl == Mutability::Mut
-                        && alloc_actual_mutbl == Mutability::Not
-                    {
-                        throw_validation_failure!(self.path, MutableRefToImmutable);
+                    // Dangling and Mutability check.
+                    let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id);
+                    if alloc_kind == AllocKind::Dead {
+                        // This can happen for zero-sized references. We can't have *any* references to
+                        // non-existing allocations in const-eval though, interning rejects them all as
+                        // the rest of rustc isn't happy with them... so we throw an error, even though
+                        // this isn't really UB.
+                        // A potential future alternative would be to resurrect this as a zero-sized allocation
+                        // (which codegen will then compile to an aligned dummy pointer anyway).
+                        throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
                     }
-                    // In a const, everything must be completely immutable.
-                    if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
+                    // If this allocation has size zero, there is no actual mutability here.
+                    if size != Size::ZERO {
+                        // Determine whether this pointer expects to be pointing to something mutable.
+                        let ptr_expected_mutbl = match ptr_kind {
+                            PointerKind::Box => Mutability::Mut,
+                            PointerKind::Ref(mutbl) => {
+                                // We do not take into account interior mutability here since we cannot know if
+                                // there really is an `UnsafeCell` inside `Option<UnsafeCell>` -- so we check
+                                // that in the recursive descent behind this reference (controlled by
+                                // `allow_immutable_unsafe_cell`).
+                                mutbl
+                            }
+                        };
+                        // Determine what it actually points to.
+                        let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
+                        // Mutable pointer to immutable memory is no good.
                         if ptr_expected_mutbl == Mutability::Mut
-                            || alloc_actual_mutbl == Mutability::Mut
+                            && alloc_actual_mutbl == Mutability::Not
                         {
-                            throw_validation_failure!(self.path, ConstRefToMutable);
+                            throw_validation_failure!(self.path, MutableRefToImmutable);
+                        }
+                        // In a const, everything must be completely immutable.
+                        if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
+                            if ptr_expected_mutbl == Mutability::Mut
+                                || alloc_actual_mutbl == Mutability::Mut
+                            {
+                                throw_validation_failure!(self.path, ConstRefToMutable);
+                            }
                         }
                     }
                 }
@@ -524,6 +535,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 if skip_recursive_check {
                     return Ok(());
                 }
+            } else {
+                // This is not CTFE, so it's Miri with recursive checking.
+                // FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized
+                // and then puts the value in there, so briefly we have a box with uninit contents.
+                // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not
+                // needed since validation reads bypass Stacked Borrows and data race checks.
+                if matches!(ptr_kind, PointerKind::Box) {
+                    return Ok(());
+                }
             }
             let path = &self.path;
             ref_tracking.track(place, || {
@@ -605,7 +625,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                     let _fn = try_validation!(
                         self.ecx.get_ptr_fn(ptr),
                         self.path,
-                        Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) =>
+                        Ub(DanglingIntPointer{ .. } | InvalidFunctionPointer(..)) =>
                             InvalidFnPtr { value: format!("{ptr}") },
                     );
                     // FIXME: Check if the signature matches
@@ -1072,11 +1092,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// `op` is assumed to cover valid memory if it is an indirect operand.
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
-    pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+    pub fn validate_operand(
+        &self,
+        op: &OpTy<'tcx, M::Provenance>,
+        recursive: bool,
+    ) -> InterpResult<'tcx> {
         // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
         // still correct to not use `ctfe_mode`: that mode is for validation of the final constant
-        // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
-        // recurse through references which, for now, we don't want here, either.
-        self.validate_operand_internal(op, vec![], None, None)
+        // value, it rules out things like `UnsafeCell` in awkward places.
+        if !recursive {
+            return self.validate_operand_internal(op, vec![], None, None);
+        }
+        // Do a recursive check.
+        let mut ref_tracking = RefTracking::empty();
+        self.validate_operand_internal(op, vec![], Some(&mut ref_tracking), None)?;
+        while let Some((mplace, path)) = ref_tracking.todo.pop() {
+            self.validate_operand_internal(&mplace.into(), path, Some(&mut ref_tracking), None)?;
+        }
+        Ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 71c057e549b..fd649d608c6 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -1,15 +1,14 @@
 //! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
 //! types until we arrive at the leaves, with custom handling for primitive types.
 
+use std::num::NonZero;
+
 use rustc_index::IndexVec;
 use rustc_middle::mir::interpret::InterpResult;
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::FieldIdx;
-use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
+use rustc_target::abi::{FieldIdx, FieldsShape, VariantIdx, Variants};
 use tracing::trace;
 
-use std::num::NonZero;
-
 use super::{throw_inval, InterpCx, MPlaceTy, Machine, Projectable};
 
 /// How to traverse a value and what to do when we are at the leaves.
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 50a4d0612cc..780404212c3 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -26,8 +26,8 @@ pub mod util;
 use std::sync::atomic::AtomicBool;
 
 pub use errors::ReportErrorExt;
-
-use rustc_middle::{ty, util::Providers};
+use rustc_middle::ty;
+use rustc_middle::util::Providers;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index 528274e6aba..5ad55968398 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -22,7 +22,7 @@ where
     };
 
     let ty = place.ty(local_decls, tcx).ty;
-    let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {});
+    let unsized_tail = || tcx.struct_tail_for_codegen(ty, param_env);
     match tcx.layout_of(param_env.and(ty)) {
         Ok(layout)
             if layout.align.abi <= pack
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 3b07bee2d9c..eb185bee5c0 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,9 +1,8 @@
 use rustc_hir::LangItem;
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Mutability};
+use rustc_middle::{bug, mir};
 use rustc_span::symbol::Symbol;
 use tracing::trace;
 
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index daf57285ebe..cbd1fdeea2a 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -1,6 +1,6 @@
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
-use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
 
 use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine};
@@ -30,10 +30,10 @@ pub fn check_validity_requirement<'tcx>(
         return Ok(!layout.abi.is_uninhabited());
     }
 
+    let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
     if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
-        might_permit_raw_init_strict(layout, tcx, kind)
+        might_permit_raw_init_strict(layout, &layout_cx, kind)
     } else {
-        let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
         might_permit_raw_init_lax(layout, &layout_cx, kind)
     }
 }
@@ -42,12 +42,12 @@ pub fn check_validity_requirement<'tcx>(
 /// details.
 fn might_permit_raw_init_strict<'tcx>(
     ty: TyAndLayout<'tcx>,
-    tcx: TyCtxt<'tcx>,
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     kind: ValidityRequirement,
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
 
-    let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
+    let mut cx = InterpCx::new(cx.tcx, rustc_span::DUMMY_SP, cx.param_env, machine);
 
     let allocated = cx
         .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
@@ -67,7 +67,7 @@ fn might_permit_raw_init_strict<'tcx>(
     // This does *not* actually check that references are dereferenceable, but since all types that
     // require dereferenceability also require non-null, we don't actually get any false negatives
     // due to this.
-    Ok(cx.validate_operand(&ot).is_ok())
+    Ok(cx.validate_operand(&ot, /*recursive*/ false).is_ok())
 }
 
 /// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 01e517250f7..3aa3b3b74e0 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -1,13 +1,11 @@
+use std::fmt::Write;
+
 use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::DisambiguatedDefPathData;
 use rustc_middle::bug;
-use rustc_middle::ty::{
-    self,
-    print::{PrettyPrinter, Print, PrintError, Printer},
-    GenericArg, GenericArgKind, Ty, TyCtxt,
-};
-use std::fmt::Write;
+use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
+use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt};
 
 struct AbsolutePathPrinter<'tcx> {
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs
index 80810df14d0..1c2321623e4 100644
--- a/compiler/rustc_data_structures/src/base_n.rs
+++ b/compiler/rustc_data_structures/src/base_n.rs
@@ -1,8 +1,7 @@
 //! Converts unsigned integers into a string representation with some base.
 //! Bases up to and including 36 can be used for case-insensitive things.
 
-use std::ascii;
-use std::fmt;
+use std::{ascii, fmt};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index 30e3d6aa86c..efc56dc9337 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,8 +1,11 @@
-use crate::stable_hasher::impl_stable_traits_for_trivial_type;
-use crate::stable_hasher::{FromStableHash, Hash64, StableHasherHash};
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::hash::{Hash, Hasher};
 
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+use crate::stable_hasher::{
+    impl_stable_traits_for_trivial_type, FromStableHash, Hash64, StableHasherHash,
+};
+
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_data_structures/src/flat_map_in_place.rs b/compiler/rustc_data_structures/src/flat_map_in_place.rs
index f58844f2817..e66b00b7557 100644
--- a/compiler/rustc_data_structures/src/flat_map_in_place.rs
+++ b/compiler/rustc_data_structures/src/flat_map_in_place.rs
@@ -1,5 +1,6 @@
-use smallvec::{Array, SmallVec};
 use std::ptr;
+
+use smallvec::{Array, SmallVec};
 use thin_vec::ThinVec;
 
 pub trait FlatMapInPlace<T>: Sized {
diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs
index eff9e8f838f..12b8b41210d 100644
--- a/compiler/rustc_data_structures/src/flock/unix.rs
+++ b/compiler/rustc_data_structures/src/flock/unix.rs
@@ -1,8 +1,7 @@
 use std::fs::{File, OpenOptions};
-use std::io;
-use std::mem;
 use std::os::unix::prelude::*;
 use std::path::Path;
+use std::{io, mem};
 
 #[derive(Debug)]
 pub struct Lock {
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index 7dc72661939..0d76df27a0a 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -2,16 +2,14 @@ use std::fs::{File, OpenOptions};
 use std::io;
 use std::os::windows::prelude::*;
 use std::path::Path;
-use tracing::debug;
 
-use windows::{
-    Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE},
-    Win32::Storage::FileSystem::{
-        LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK,
-        LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS,
-    },
-    Win32::System::IO::OVERLAPPED,
+use tracing::debug;
+use windows::Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE};
+use windows::Win32::Storage::FileSystem::{
+    LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK,
+    LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS,
 };
+use windows::Win32::System::IO::OVERLAPPED;
 
 #[derive(Debug)]
 pub struct Lock {
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index d1d2de670b8..7cb013fdbd8 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -9,10 +9,11 @@
 //! Thomas Lengauer and Robert Endre Tarjan.
 //! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
 
-use super::ControlFlowGraph;
+use std::cmp::Ordering;
+
 use rustc_index::{Idx, IndexSlice, IndexVec};
 
-use std::cmp::Ordering;
+use super::ControlFlowGraph;
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
index 39725ba4301..6c078ca7c6e 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
@@ -1,6 +1,5 @@
-use super::*;
-
 use super::super::tests::TestGraph;
+use super::*;
 
 #[test]
 fn diamond() {
diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
index 8cf4b4153db..43fdfe6ee0d 100644
--- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
@@ -20,8 +20,9 @@
 //! the field `next_edge`). Each of those fields is an array that should
 //! be indexed by the direction (see the type `Direction`).
 
-use rustc_index::bit_set::BitSet;
 use std::fmt::Debug;
+
+use rustc_index::bit_set::BitSet;
 use tracing::debug;
 
 #[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs
index b4dbd65db94..32a6d9ec881 100644
--- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/implementation/tests.rs
@@ -1,6 +1,7 @@
-use crate::graph::implementation::*;
 use tracing::debug;
 
+use crate::graph::implementation::*;
+
 type TestGraph = Graph<&'static str, &'static str>;
 
 fn create_graph() -> TestGraph {
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 6fca57d32f7..cbc6664d853 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -1,7 +1,9 @@
-use super::{DirectedGraph, StartNode, Successors};
+use std::ops::ControlFlow;
+
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
-use std::ops::ControlFlow;
+
+use super::{DirectedGraph, StartNode, Successors};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs
index c498c289337..eb7d0bd14b6 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs
@@ -1,5 +1,4 @@
 use super::super::tests::TestGraph;
-
 use super::*;
 
 #[test]
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 8b96b36a851..2a457ffb70b 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -8,14 +8,17 @@
 //! Typical examples would include: minimum element in SCC, maximum element
 //! reachable from it, etc.
 
-use crate::fx::FxHashSet;
-use crate::graph::vec_graph::VecGraph;
-use crate::graph::{DirectedGraph, NumEdges, Successors};
-use rustc_index::{Idx, IndexSlice, IndexVec};
+use std::assert_matches::debug_assert_matches;
 use std::fmt::Debug;
 use std::ops::Range;
+
+use rustc_index::{Idx, IndexSlice, IndexVec};
 use tracing::{debug, instrument};
 
+use crate::fx::FxHashSet;
+use crate::graph::vec_graph::VecGraph;
+use crate::graph::{DirectedGraph, NumEdges, Successors};
+
 #[cfg(test)]
 mod tests;
 
@@ -567,7 +570,7 @@ where
                     // This None marks that we still have the initialize this node's frame.
                     debug!(?depth, ?node);
 
-                    debug_assert!(matches!(self.node_states[node], NodeState::NotVisited));
+                    debug_assert_matches!(self.node_states[node], NodeState::NotVisited);
 
                     // Push `node` onto the stack.
                     self.node_states[node] = NodeState::BeingVisited {
diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs
index 85c2703cc25..b69b9dbc4a8 100644
--- a/compiler/rustc_data_structures/src/graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/tests.rs
@@ -1,7 +1,7 @@
-use crate::fx::FxHashMap;
 use std::cmp::max;
 
 use super::*;
+use crate::fx::FxHashMap;
 
 pub struct TestGraph {
     num_nodes: usize,
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 120244c8918..96784c2540a 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -1,6 +1,7 @@
-use crate::graph::{DirectedGraph, NumEdges, Predecessors, Successors};
 use rustc_index::{Idx, IndexVec};
 
+use crate::graph::{DirectedGraph, NumEdges, Predecessors, Successors};
+
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
index a077d9d0813..78caf75f5b4 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
@@ -1,6 +1,5 @@
-use crate::graph;
-
 use super::*;
+use crate::graph;
 
 fn create_graph() -> VecGraph<usize> {
     // Create a simple graph
diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs
index ef5d2e845ef..f98c8de1eb0 100644
--- a/compiler/rustc_data_structures/src/hashes.rs
+++ b/compiler/rustc_data_structures/src/hashes.rs
@@ -11,11 +11,13 @@
 //! connect the fact that they can only be produced by a `StableHasher` to their
 //! `Encode`/`Decode` impls.
 
-use crate::stable_hasher::{FromStableHash, StableHasherHash};
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
 use std::ops::BitXorAssign;
 
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+use crate::stable_hasher::{FromStableHash, StableHasherHash};
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
 pub struct Hash64 {
     inner: u64,
diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs
index e0f8c350c2a..850b052f564 100644
--- a/compiler/rustc_data_structures/src/intern.rs
+++ b/compiler/rustc_data_structures/src/intern.rs
@@ -1,10 +1,11 @@
-use crate::stable_hasher::{HashStable, StableHasher};
 use std::cmp::Ordering;
 use std::fmt::{self, Debug};
 use std::hash::{Hash, Hasher};
 use std::ops::Deref;
 use std::ptr;
 
+use crate::stable_hasher::{HashStable, StableHasher};
+
 mod private {
     #[derive(Clone, Copy, Debug)]
     pub struct PrivateZst;
diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs
index 89088bc5c1b..d09f7efc8ff 100644
--- a/compiler/rustc_data_structures/src/jobserver.rs
+++ b/compiler/rustc_data_structures/src/jobserver.rs
@@ -1,9 +1,8 @@
-pub use jobserver_crate::Client;
+use std::sync::{LazyLock, OnceLock};
 
+pub use jobserver_crate::Client;
 use jobserver_crate::{FromEnv, FromEnvErrorKind};
 
-use std::sync::{LazyLock, OnceLock};
-
 // We can only call `from_env_ext` once per process
 
 // We stick this in a global because there could be multiple rustc instances
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 3f18b036940..a35f5b1f17d 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -10,7 +10,6 @@
 #![allow(internal_features)]
 #![allow(rustc::default_hash_types)]
 #![allow(rustc::potential_query_instability)]
-#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![cfg_attr(not(parallel_compiler), feature(cell_leak))]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
@@ -19,6 +18,7 @@
 #![feature(array_windows)]
 #![feature(ascii_char)]
 #![feature(ascii_char_variants)]
+#![feature(assert_matches)]
 #![feature(auto_traits)]
 #![feature(cfg_match)]
 #![feature(core_intrinsics)]
@@ -39,14 +39,12 @@
 #![feature(unwrap_infallible)]
 // tidy-alphabetical-end
 
+use std::fmt;
+
 pub use atomic_ref::AtomicRef;
-pub use ena::snapshot_vec;
-pub use ena::undo_log;
-pub use ena::unify;
+pub use ena::{snapshot_vec, undo_log, unify};
 pub use rustc_index::static_assert_size;
 
-use std::fmt;
-
 pub mod aligned;
 pub mod base_n;
 pub mod binary_search_util;
diff --git a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs
index 4b6aa116520..60cde9a52b4 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs
@@ -1,11 +1,12 @@
-use crate::obligation_forest::{ForestObligation, ObligationForest};
-use rustc_graphviz as dot;
 use std::env::var_os;
 use std::fs::File;
 use std::io::BufWriter;
 use std::path::Path;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+use rustc_graphviz as dot;
+
+use crate::obligation_forest::{ForestObligation, ObligationForest};
 
 impl<O: ForestObligation> ObligationForest<O> {
     /// Creates a graphviz representation of the obligation forest. Given a directory this will
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 3883b0736db..cfe7dd13e80 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -69,14 +69,16 @@
 //! step, we compress the vector to remove completed and error nodes, which
 //! aren't needed anymore.
 
-use crate::fx::{FxHashMap, FxHashSet};
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash;
 use std::marker::PhantomData;
+
 use tracing::debug;
 
+use crate::fx::{FxHashMap, FxHashSet};
+
 mod graphviz;
 
 #[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
index d09c8e54436..a58c6ee1bcc 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
@@ -1,7 +1,7 @@
-use super::*;
-
 use std::fmt;
 
+use super::*;
+
 impl<'a> super::ForestObligation for &'a str {
     type CacheKey = &'a str;
 
diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs
index bb664795860..bbe6691e548 100644
--- a/compiler/rustc_data_structures/src/owned_slice.rs
+++ b/compiler/rustc_data_structures/src/owned_slice.rs
@@ -1,10 +1,11 @@
-use std::{borrow::Borrow, ops::Deref};
+use std::borrow::Borrow;
+use std::ops::Deref;
 
-use crate::sync::Lrc;
 // Use our fake Send/Sync traits when on not parallel compiler,
 // so that `OwnedSlice` only implements/requires Send/Sync
 // for parallel compiler builds.
 use crate::sync;
+use crate::sync::Lrc;
 
 /// An owned slice.
 ///
diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs
index 520871a12be..324b8ecf2d3 100644
--- a/compiler/rustc_data_structures/src/owned_slice/tests.rs
+++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs
@@ -1,15 +1,9 @@
-use std::{
-    ops::Deref,
-    sync::{
-        atomic::{self, AtomicBool},
-        Arc,
-    },
-};
-
-use crate::{
-    defer,
-    owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
-};
+use std::ops::Deref;
+use std::sync::atomic::{self, AtomicBool};
+use std::sync::Arc;
+
+use crate::defer;
+use crate::owned_slice::{slice_owned, try_slice_owned, OwnedSlice};
 
 #[test]
 fn smoke() {
diff --git a/compiler/rustc_data_structures/src/packed.rs b/compiler/rustc_data_structures/src/packed.rs
index 0a392d91988..f54b12b5b53 100644
--- a/compiler/rustc_data_structures/src/packed.rs
+++ b/compiler/rustc_data_structures/src/packed.rs
@@ -1,8 +1,10 @@
-use crate::stable_hasher::{HashStable, StableHasher};
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::cmp::Ordering;
 use std::fmt;
 
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+use crate::stable_hasher::{HashStable, StableHasher};
+
 /// A packed 128-bit integer. Useful for reducing the size of structures in
 /// some cases.
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 240f2671c3b..19050746c2f 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -81,19 +81,15 @@
 //!
 //! [mm]: https://github.com/rust-lang/measureme/
 
-use crate::fx::FxHashMap;
-use crate::outline;
-
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
 use std::error::Error;
 use std::fmt::Display;
-use std::fs;
 use std::intrinsics::unlikely;
 use std::path::Path;
-use std::process;
 use std::sync::Arc;
 use std::time::{Duration, Instant};
+use std::{fs, process};
 
 pub use measureme::EventId;
 use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
@@ -101,6 +97,9 @@ use parking_lot::RwLock;
 use smallvec::SmallVec;
 use tracing::warn;
 
+use crate::fx::FxHashMap;
+use crate::outline;
+
 bitflags::bitflags! {
     #[derive(Clone, Copy)]
     struct EventFilter: u16 {
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 4b02b183460..03aa1d8f678 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,14 +1,15 @@
+use std::borrow::Borrow;
+use std::collections::hash_map::RawEntryMut;
+use std::hash::{Hash, Hasher};
+use std::{iter, mem};
+
+#[cfg(parallel_compiler)]
+use either::Either;
+
 use crate::fx::{FxHashMap, FxHasher};
 #[cfg(parallel_compiler)]
 use crate::sync::{is_dyn_thread_safe, CacheAligned};
 use crate::sync::{Lock, LockGuard, Mode};
-#[cfg(parallel_compiler)]
-use either::Either;
-use std::borrow::Borrow;
-use std::collections::hash_map::RawEntryMut;
-use std::hash::{Hash, Hasher};
-use std::iter;
-use std::mem;
 
 // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
 // but this should be tested on higher core count CPUs. How the `Sharded` type gets used
diff --git a/compiler/rustc_data_structures/src/snapshot_map/mod.rs b/compiler/rustc_data_structures/src/snapshot_map/mod.rs
index 8a50179cd3b..d50365b6b06 100644
--- a/compiler/rustc_data_structures/src/snapshot_map/mod.rs
+++ b/compiler/rustc_data_structures/src/snapshot_map/mod.rs
@@ -1,11 +1,11 @@
-use crate::fx::FxHashMap;
-use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog};
 use std::borrow::{Borrow, BorrowMut};
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::ops;
 
+use crate::fx::FxHashMap;
 pub use crate::undo_log::Snapshot;
+use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 885f023122a..066ea03b4ac 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -1,10 +1,12 @@
-use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
-use rustc_macros::{Decodable_Generic, Encodable_Generic};
 use std::borrow::Borrow;
 use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
+use rustc_macros::{Decodable_Generic, Encodable_Generic};
+
+use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
+
 mod index_map;
 
 pub use index_map::SortedIndexMultiMap;
diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index c172ee1c970..e9a5fb51975 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -2,9 +2,10 @@
 
 use std::hash::{Hash, Hasher};
 
-use crate::stable_hasher::{HashStable, StableHasher};
 use rustc_index::{Idx, IndexVec};
 
+use crate::stable_hasher::{HashStable, StableHasher};
+
 /// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
 /// an item by key and *O*(1) lookup by index.
 ///
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index 2ef4a2ccd84..3200249a2dc 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -1,10 +1,12 @@
-use crate::fx::FxHashMap;
-use arrayvec::ArrayVec;
-use either::Either;
 use std::fmt;
 use std::hash::Hash;
 use std::ops::Index;
 
+use arrayvec::ArrayVec;
+use either::Either;
+
+use crate::fx::FxHashMap;
+
 /// For pointer-sized arguments arrays
 /// are faster than set/map for up to 64
 /// arguments.
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 83883eeba9c..9673f94d7a4 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -1,19 +1,20 @@
-use rustc_index::bit_set::{self, BitSet};
-use rustc_index::{Idx, IndexSlice, IndexVec};
-use smallvec::SmallVec;
 use std::hash::{BuildHasher, Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
 use std::num::NonZero;
 
+use rustc_index::bit_set::{self, BitSet};
+use rustc_index::{Idx, IndexSlice, IndexVec};
+use smallvec::SmallVec;
+
 #[cfg(test)]
 mod tests;
 
-pub use crate::hashes::{Hash128, Hash64};
+pub use rustc_stable_hash::{
+    FromStableHash, SipHasher128Hash as StableHasherHash, StableSipHasher128 as StableHasher,
+};
 
-pub use rustc_stable_hash::FromStableHash;
-pub use rustc_stable_hash::SipHasher128Hash as StableHasherHash;
-pub use rustc_stable_hash::StableSipHasher128 as StableHasher;
+pub use crate::hashes::{Hash128, Hash64};
 
 /// 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/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index 9a0fd52677d..0f2c0eee27d 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -51,6 +51,15 @@ impl<T> Steal<T> {
         let value = value_ref.take();
         value.expect("attempt to steal from stolen value")
     }
+
+    /// Writers of rustc drivers often encounter stealing issues. This function makes it possible to
+    /// handle these errors gracefully.
+    ///
+    /// This should not be used within rustc as it leaks information not tracked
+    /// by the query system, breaking incremental compilation.
+    pub fn is_stolen(&self) -> bool {
+        self.value.borrow().is_none()
+    }
 }
 
 impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> {
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index 38629ea9801..391a7c9f30d 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -5,10 +5,12 @@
 //! mismatches where we have two versions of the same crate that were
 //! compiled from distinct sources.
 
+use std::fmt;
+
+use rustc_macros::{Decodable_Generic, Encodable_Generic};
+
 use crate::fingerprint::Fingerprint;
 use crate::stable_hasher;
-use rustc_macros::{Decodable_Generic, Encodable_Generic};
-use std::fmt;
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)]
 pub struct Svh {
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 058a675c40d..6df94bc0e94 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -41,10 +41,11 @@
 //!
 //! [^2]: `MTRef`, `MTLockRef` are type aliases.
 
-pub use crate::marker::*;
 use std::collections::HashMap;
 use std::hash::{BuildHasher, Hash};
 
+pub use crate::marker::*;
+
 mod lock;
 #[doc(no_inline)]
 pub use lock::{Lock, LockGuard, Mode};
@@ -56,7 +57,6 @@ mod parallel;
 #[cfg(parallel_compiler)]
 pub use parallel::scope;
 pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in};
-
 pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
 
 mod vec;
diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs
index 466c44f59bb..fad5f583d1c 100644
--- a/compiler/rustc_data_structures/src/sync/freeze.rs
+++ b/compiler/rustc_data_structures/src/sync/freeze.rs
@@ -1,14 +1,13 @@
+use std::cell::UnsafeCell;
+use std::intrinsics::likely;
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+use std::ptr::NonNull;
+use std::sync::atomic::Ordering;
+
 use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard};
 #[cfg(parallel_compiler)]
 use crate::sync::{DynSend, DynSync};
-use std::{
-    cell::UnsafeCell,
-    intrinsics::likely,
-    marker::PhantomData,
-    ops::{Deref, DerefMut},
-    ptr::NonNull,
-    sync::atomic::Ordering,
-};
 
 /// A type which allows mutation using a lock until
 /// the value is frozen and can be accessed lock-free.
diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs
index 780be773945..7cf942685e3 100644
--- a/compiler/rustc_data_structures/src/sync/lock.rs
+++ b/compiler/rustc_data_structures/src/sync/lock.rs
@@ -19,19 +19,20 @@ pub enum Mode {
 }
 
 mod maybe_sync {
-    use super::Mode;
-    use crate::sync::mode;
-    #[cfg(parallel_compiler)]
-    use crate::sync::{DynSend, DynSync};
-    use parking_lot::lock_api::RawMutex as _;
-    use parking_lot::RawMutex;
-    use std::cell::Cell;
-    use std::cell::UnsafeCell;
+    use std::cell::{Cell, UnsafeCell};
     use std::intrinsics::unlikely;
     use std::marker::PhantomData;
     use std::mem::ManuallyDrop;
     use std::ops::{Deref, DerefMut};
 
+    use parking_lot::lock_api::RawMutex as _;
+    use parking_lot::RawMutex;
+
+    use super::Mode;
+    use crate::sync::mode;
+    #[cfg(parallel_compiler)]
+    use crate::sync::{DynSend, DynSync};
+
     /// A guard holding mutable access to a `Lock` which is in a locked state.
     #[must_use = "if unused the Lock will immediately unlock"]
     pub struct LockGuard<'a, T> {
@@ -186,12 +187,12 @@ mod maybe_sync {
 }
 
 mod no_sync {
-    use super::Mode;
     use std::cell::RefCell;
-
     #[doc(no_inline)]
     pub use std::cell::RefMut as LockGuard;
 
+    use super::Mode;
+
     pub struct Lock<T>(RefCell<T>);
 
     impl<T> Lock<T> {
diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs
index 7783de57fba..2b89431c2ed 100644
--- a/compiler/rustc_data_structures/src/sync/parallel.rs
+++ b/compiler/rustc_data_structures/src/sync/parallel.rs
@@ -3,9 +3,6 @@
 
 #![allow(dead_code)]
 
-use crate::sync::IntoDynSyncSend;
-use crate::FatalErrorMarker;
-use parking_lot::Mutex;
 use std::any::Any;
 use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
 
@@ -13,6 +10,10 @@ use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
 pub use disabled::*;
 #[cfg(parallel_compiler)]
 pub use enabled::*;
+use parking_lot::Mutex;
+
+use crate::sync::IntoDynSyncSend;
+use crate::FatalErrorMarker;
 
 /// A guard used to hold panics that occur during a parallel section to later by unwound.
 /// This is used for the parallel compiler to prevent fatal errors from non-deterministically
diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs
index 07a361ba260..4950481d311 100644
--- a/compiler/rustc_data_structures/src/sync/worker_local.rs
+++ b/compiler/rustc_data_structures/src/sync/worker_local.rs
@@ -1,11 +1,10 @@
-use parking_lot::Mutex;
-use std::cell::Cell;
-use std::cell::OnceCell;
+use std::cell::{Cell, OnceCell};
 use std::num::NonZero;
 use std::ops::Deref;
 use std::ptr;
 use std::sync::Arc;
 
+use parking_lot::Mutex;
 #[cfg(parallel_compiler)]
 use {crate::outline, crate::sync::CacheAligned};
 
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index 8b9e834b60b..25e107b0f41 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -1,5 +1,3 @@
-use super::{Pointer, Tag};
-use crate::stable_hasher::{HashStable, StableHasher};
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
@@ -8,6 +6,9 @@ use std::num::NonZero;
 use std::ops::{Deref, DerefMut};
 use std::ptr::NonNull;
 
+use super::{Pointer, Tag};
+use crate::stable_hasher::{HashStable, StableHasher};
+
 /// A [`Copy`] tagged pointer.
 ///
 /// This is essentially `{ pointer: P, tag: T }` packed in a single pointer.
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
index 4e42b5b4afe..319a8cdd399 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
@@ -2,8 +2,7 @@ use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::ops::{Deref, DerefMut};
 
-use super::CopyTaggedPtr;
-use super::{Pointer, Tag};
+use super::{CopyTaggedPtr, Pointer, Tag};
 use crate::stable_hasher::{HashStable, StableHasher};
 
 /// A tagged pointer that supports pointers that implement [`Drop`].
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
index 2c17d678d3a..4d342c72cc5 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
@@ -1,4 +1,5 @@
-use std::{ptr, sync::Arc};
+use std::ptr;
+use std::sync::Arc;
 
 use crate::tagged_ptr::{Pointer, Tag, Tag2, TaggedPtr};
 
diff --git a/compiler/rustc_data_structures/src/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs
index 621d3011a2a..4dbe11d707d 100644
--- a/compiler/rustc_data_structures/src/temp_dir.rs
+++ b/compiler/rustc_data_structures/src/temp_dir.rs
@@ -1,5 +1,6 @@
 use std::mem::ManuallyDrop;
 use std::path::Path;
+
 use tempfile::TempDir;
 
 /// This is used to avoid TempDir being dropped on error paths unintentionally.
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index cd391fe357a..e81ebb9a4be 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -1,11 +1,13 @@
-use crate::frozen::Frozen;
-use crate::fx::{FxHashSet, FxIndexSet};
-use rustc_index::bit_set::BitMatrix;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::mem;
 use std::ops::Deref;
 
+use rustc_index::bit_set::BitMatrix;
+
+use crate::frozen::Frozen;
+use crate::fx::{FxHashSet, FxIndexSet};
+
 #[cfg(test)]
 mod tests;
 
@@ -201,9 +203,9 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
     /// exists). See `postdom_upper_bound` for details.
     pub fn mutual_immediate_postdominator(&self, mut mubs: Vec<T>) -> Option<T> {
         loop {
-            match mubs.len() {
-                0 => return None,
-                1 => return Some(mubs[0]),
+            match mubs[..] {
+                [] => return None,
+                [mub] => return Some(mub),
                 _ => {
                     let m = mubs.pop().unwrap();
                     let n = mubs.pop().unwrap();
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
index 1ccd22a56c9..bafb16a8b5e 100644
--- a/compiler/rustc_data_structures/src/unord.rs
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -2,21 +2,17 @@
 //! ordering. This is a useful property for deterministic computations, such
 //! as required by the query system.
 
+use std::borrow::{Borrow, BorrowMut};
+use std::collections::hash_map::{Entry, OccupiedError};
+use std::hash::Hash;
+use std::iter::{Product, Sum};
+use std::ops::Index;
+
 use rustc_hash::{FxHashMap, FxHashSet};
 use rustc_macros::{Decodable_Generic, Encodable_Generic};
-use std::collections::hash_map::OccupiedError;
-use std::{
-    borrow::{Borrow, BorrowMut},
-    collections::hash_map::Entry,
-    hash::Hash,
-    iter::{Product, Sum},
-    ops::Index,
-};
-
-use crate::{
-    fingerprint::Fingerprint,
-    stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey},
-};
+
+use crate::fingerprint::Fingerprint;
+use crate::stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey};
 
 /// `UnordItems` is the order-less version of `Iterator`. It only contains methods
 /// that don't (easily) expose an ordering of the underlying items.
diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs
index 9db6b6f20be..490d7d3ddd5 100644
--- a/compiler/rustc_data_structures/src/work_queue.rs
+++ b/compiler/rustc_data_structures/src/work_queue.rs
@@ -1,6 +1,7 @@
+use std::collections::VecDeque;
+
 use rustc_index::bit_set::BitSet;
 use rustc_index::Idx;
-use std::collections::VecDeque;
 
 /// A work queue is a handy data structure for tracking work left to
 /// do. (For example, basic blocks left to process.) It is basically a
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index ad2acb03b3f..2b7dc040f64 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -17,8 +17,23 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
+use std::cmp::max;
+use std::collections::BTreeMap;
+use std::ffi::OsString;
+use std::fmt::Write as _;
+use std::fs::{self, File};
+use std::io::{self, IsTerminal, Read, Write};
+use std::panic::{self, catch_unwind, PanicHookInfo};
+use std::path::PathBuf;
+use std::process::{self, Command, Stdio};
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::{Arc, OnceLock};
+use std::time::{Duration, Instant, SystemTime};
+use std::{env, str};
+
 use rustc_ast as ast;
-use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
+use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_codegen_ssa::{CodegenErrors, CodegenResults};
 use rustc_const_eval::CTRL_C_RECEIVED;
 use rustc_data_structures::profiling::{
     get_resident_set_size, print_time_passes_entry, TimePassesFormat,
@@ -35,8 +50,10 @@ use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
-use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
-use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType};
+use rustc_session::config::{
+    nightly_options, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, CG_OPTIONS,
+    Z_OPTIONS,
+};
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::output::collect_crate_types;
@@ -46,20 +63,6 @@ use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use rustc_target::json::ToJson;
 use rustc_target::spec::{Target, TargetTriple};
-use std::cmp::max;
-use std::collections::BTreeMap;
-use std::env;
-use std::ffi::OsString;
-use std::fmt::Write as _;
-use std::fs::{self, File};
-use std::io::{self, IsTerminal, Read, Write};
-use std::panic::{self, catch_unwind, PanicHookInfo};
-use std::path::PathBuf;
-use std::process::{self, Command, Stdio};
-use std::str;
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, OnceLock};
-use std::time::{Duration, Instant, SystemTime};
 use time::OffsetDateTime;
 use tracing::trace;
 
@@ -299,6 +302,8 @@ fn run_compiler(
     let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) };
 
     let sopts = config::build_session_options(&mut default_early_dcx, &matches);
+    // fully initialize ice path static once unstable options are available as context
+    let ice_file = ice_path_with_config(Some(&sopts.unstable_opts)).clone();
 
     if let Some(ref code) = matches.opt_str("explain") {
         handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color);
@@ -313,7 +318,7 @@ fn run_compiler(
         input: Input::File(PathBuf::new()),
         output_file: ofile,
         output_dir: odir,
-        ice_file: ice_path().clone(),
+        ice_file,
         file_loader,
         locale_resources: DEFAULT_LOCALE_RESOURCES,
         lint_caps: Default::default(),
@@ -333,12 +338,11 @@ fn run_compiler(
             config.input = input;
             true // has input: normal compilation
         }
-        Ok(None) => match matches.free.len() {
-            0 => false, // no input: we will exit early
-            1 => panic!("make_input should have provided valid inputs"),
-            _ => default_early_dcx.early_fatal(format!(
-                "multiple input filenames provided (first two filenames are `{}` and `{}`)",
-                matches.free[0], matches.free[1],
+        Ok(None) => match matches.free.as_slice() {
+            [] => false, // no input: we will exit early
+            [_] => panic!("make_input should have provided valid inputs"),
+            [fst, snd, ..] => default_early_dcx.early_fatal(format!(
+                "multiple input filenames provided (first two filenames are `{fst}` and `{snd}`)"
             )),
         },
     };
@@ -486,34 +490,30 @@ fn make_input(
     early_dcx: &EarlyDiagCtxt,
     free_matches: &[String],
 ) -> Result<Option<Input>, ErrorGuaranteed> {
-    if free_matches.len() == 1 {
-        let ifile = &free_matches[0];
-        if ifile == "-" {
-            let mut src = String::new();
-            if io::stdin().read_to_string(&mut src).is_err() {
-                // Immediately stop compilation if there was an issue reading
-                // the input (for example if the input stream is not UTF-8).
-                let reported = early_dcx
-                    .early_err("couldn't read from stdin, as it did not contain valid UTF-8");
-                return Err(reported);
-            }
-            if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
-                let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
-                    "when UNSTABLE_RUSTDOC_TEST_PATH is set \
+    let [ifile] = free_matches else { return Ok(None) };
+    if ifile == "-" {
+        let mut src = String::new();
+        if io::stdin().read_to_string(&mut src).is_err() {
+            // Immediately stop compilation if there was an issue reading
+            // the input (for example if the input stream is not UTF-8).
+            let reported =
+                early_dcx.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
+            return Err(reported);
+        }
+        if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
+            let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
+                "when UNSTABLE_RUSTDOC_TEST_PATH is set \
                                     UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
-                );
-                let line = isize::from_str_radix(&line, 10)
-                    .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
-                let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
-                Ok(Some(Input::Str { name: file_name, input: src }))
-            } else {
-                Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
-            }
+            );
+            let line = isize::from_str_radix(&line, 10)
+                .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
+            let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
+            Ok(Some(Input::Str { name: file_name, input: src }))
         } else {
-            Ok(Some(Input::File(PathBuf::from(ifile))))
+            Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
         }
     } else {
-        Ok(None)
+        Ok(Some(Input::File(PathBuf::from(ifile))))
     }
 }
 
@@ -689,7 +689,6 @@ fn print_crate_info(
     parse_attrs: bool,
 ) -> Compilation {
     use rustc_session::config::PrintKind::*;
-
     // This import prevents the following code from using the printing macros
     // used by the rest of the module. Within this function, we only write to
     // the output specified by `sess.io.output_file`.
@@ -908,6 +907,15 @@ pub fn version_at_macro_invocation(
 ) {
     let verbose = matches.opt_present("verbose");
 
+    let mut version = version;
+    let mut release = release;
+    let tmp;
+    if let Ok(force_version) = std::env::var("RUSTC_OVERRIDE_VERSION_STRING") {
+        tmp = force_version;
+        version = &tmp;
+        release = &tmp;
+    }
+
     safe_println!("{binary} {version}");
 
     if verbose {
@@ -1296,25 +1304,43 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
 
 static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
 
+// This function should only be called from the ICE hook.
+//
+// The intended behavior is that `run_compiler` will invoke `ice_path_with_config` early in the
+// initialization process to properly initialize the ICE_PATH static based on parsed CLI flags.
+//
+// Subsequent calls to either function will then return the proper ICE path as configured by
+// the environment and cli flags
 fn ice_path() -> &'static Option<PathBuf> {
+    ice_path_with_config(None)
+}
+
+fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<PathBuf> {
+    if ICE_PATH.get().is_some() && config.is_some() && cfg!(debug_assertions) {
+        tracing::warn!(
+            "ICE_PATH has already been initialized -- files may be emitted at unintended paths"
+        )
+    }
+
     ICE_PATH.get_or_init(|| {
         if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
             return None;
         }
-        if let Some(s) = std::env::var_os("RUST_BACKTRACE")
-            && s == "0"
-        {
-            return None;
-        }
         let mut path = match std::env::var_os("RUSTC_ICE") {
             Some(s) => {
                 if s == "0" {
                     // Explicitly opting out of writing ICEs to disk.
                     return None;
                 }
+                if let Some(unstable_opts) = config && unstable_opts.metrics_dir.is_some() {
+                    tracing::warn!("ignoring -Zerror-metrics in favor of RUSTC_ICE for destination of ICE report files");
+                }
                 PathBuf::from(s)
             }
-            None => std::env::current_dir().unwrap_or_default(),
+            None => config
+                .and_then(|unstable_opts| unstable_opts.metrics_dir.to_owned())
+                .or_else(|| std::env::current_dir().ok())
+                .unwrap_or_default(),
         };
         let now: OffsetDateTime = SystemTime::now().into();
         let file_now = now
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 31de0a747b2..c973fcec0e1 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -1,9 +1,10 @@
 //! The various pretty-printing routines.
 
-use rustc_ast as ast;
+use std::cell::Cell;
+use std::fmt::Write;
+
 use rustc_ast_pretty::pprust as pprust_ast;
 use rustc_errors::FatalError;
-use rustc_hir_pretty as pprust_hir;
 use rustc_middle::bug;
 use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
 use rustc_middle::ty::{self, TyCtxt};
@@ -12,9 +13,8 @@ use rustc_session::Session;
 use rustc_smir::rustc_internal::pretty::write_smir_pretty;
 use rustc_span::symbol::Ident;
 use rustc_span::FileName;
-use std::cell::Cell;
-use std::fmt::Write;
 use tracing::debug;
+use {rustc_ast as ast, rustc_hir_pretty as pprust_hir};
 
 pub use self::PpMode::*;
 pub use self::PpSourceMode::*;
diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs
index 441219eec90..51f2a508cf9 100644
--- a/compiler/rustc_driver_impl/src/signal_handler.rs
+++ b/compiler/rustc_driver_impl/src/signal_handler.rs
@@ -1,10 +1,11 @@
 //! Signal handler for rustc
 //! Primarily used to extract a backtrace from stack overflow
 
-use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
 use std::alloc::{alloc, Layout};
 use std::{fmt, mem, ptr};
 
+use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
+
 extern "C" {
     fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int);
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0517.md b/compiler/rustc_error_codes/src/error_codes/E0517.md
index ae802245bd1..5354a08bf31 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0517.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0517.md
@@ -25,14 +25,17 @@ impl Foo {
 These attributes do not work on typedefs, since typedefs are just aliases.
 
 Representations like `#[repr(u8)]`, `#[repr(i64)]` are for selecting the
-discriminant size for enums with no data fields on any of the variants, e.g.
-`enum Color {Red, Blue, Green}`, effectively setting the size of the enum to
-the size of the provided type. Such an enum can be cast to a value of the same
-type as well. In short, `#[repr(u8)]` makes the enum behave like an integer
-with a constrained set of allowed values.
+discriminant size for enums. For enums with no data fields on any of the
+variants, e.g. `enum Color {Red, Blue, Green}`, this effectively sets the size
+of the enum to the size of the provided type. Such an enum can be cast to a
+value of the same type as well. In short, `#[repr(u8)]` makes a field-less enum
+behave like an integer with a constrained set of allowed values.
 
-Only field-less enums can be cast to numerical primitives, so this attribute
-will not apply to structs.
+For a description of how `#[repr(C)]` and representations like `#[repr(u8)]`
+affect the layout of enums with data fields, see [RFC 2195][rfc2195].
+
+Only field-less enums can be cast to numerical primitives. Representations like
+`#[repr(u8)]` will not apply to structs.
 
 `#[repr(packed)]` reduces padding to make the struct size smaller. The
 representation of enums isn't strictly defined in Rust, and this attribute
@@ -42,3 +45,5 @@ won't work on enums.
 types (i.e., `u8`, `i32`, etc) a representation that permits vectorization via
 SIMD. This doesn't make much sense for enums since they don't consist of a
 single list of data.
+
+[rfc2195]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
diff --git a/compiler/rustc_error_codes/src/error_codes/E0795.md b/compiler/rustc_error_codes/src/error_codes/E0795.md
index ad77d72c913..69e61f7738f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0795.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0795.md
@@ -3,7 +3,7 @@ Invalid argument for the `offset_of!` macro.
 Erroneous code example:
 
 ```compile_fail,E0795
-#![feature(offset_of_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 let x = std::mem::offset_of!(Option<u8>, Some);
 ```
@@ -16,7 +16,7 @@ The offset of the contained `u8` in the `Option<u8>` can be found by specifying
 the field name `0`:
 
 ```
-#![feature(offset_of_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 let x: usize = std::mem::offset_of!(Option<u8>, Some.0);
 ```
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 26a68454ab3..87dee2898da 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -6,31 +6,28 @@
 #![feature(type_alias_impl_trait)]
 // tidy-alphabetical-end
 
-use fluent_bundle::FluentResource;
-use fluent_syntax::parser::ParserError;
-use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
-use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
-use rustc_macros::{Decodable, Encodable};
-use rustc_span::Span;
 use std::borrow::Cow;
-use std::error::Error;
-use std::fmt;
-use std::fs;
-use std::io;
-use std::path::{Path, PathBuf};
-use tracing::{instrument, trace};
-
 #[cfg(not(parallel_compiler))]
 use std::cell::LazyCell as Lazy;
+use std::error::Error;
+use std::path::{Path, PathBuf};
 #[cfg(parallel_compiler)]
 use std::sync::LazyLock as Lazy;
+use std::{fmt, fs, io};
 
+pub use fluent_bundle::types::FluentType;
+use fluent_bundle::FluentResource;
+pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
+use fluent_syntax::parser::ParserError;
+use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
 #[cfg(parallel_compiler)]
 use intl_memoizer::concurrent::IntlLangMemoizer;
 #[cfg(not(parallel_compiler))]
 use intl_memoizer::IntlLangMemoizer;
-
-pub use fluent_bundle::{self, types::FluentType, FluentArgs, FluentError, FluentValue};
+use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
+use rustc_macros::{Decodable, Encodable};
+use rustc_span::Span;
+use tracing::{instrument, trace};
 pub use unic_langid::{langid, LanguageIdentifier};
 
 pub type FluentBundle =
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index b71b93cc67c..df4e9792f95 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -5,6 +5,12 @@
 //!
 //! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/
 
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
+use rustc_data_structures::sync::Lrc;
+use rustc_error_messages::FluentArgs;
+use rustc_span::source_map::SourceMap;
+use rustc_span::SourceFile;
+
 use crate::emitter::FileWithAnnotatedLines;
 use crate::snippet::Line;
 use crate::translation::{to_fluent_args, Translate};
@@ -12,11 +18,6 @@ use crate::{
     CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, FluentBundle, LazyFallbackBundle,
     Level, MultiSpan, Style, Subdiag,
 };
-use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
-use rustc_data_structures::sync::Lrc;
-use rustc_error_messages::FluentArgs;
-use rustc_span::source_map::SourceMap;
-use rustc_span::SourceFile;
 
 /// Generates diagnostics using annotate-snippet
 pub struct AnnotateSnippetEmitter {
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index d500f6d88a0..fae8b5647fc 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1,16 +1,3 @@
-use crate::snippet::Style;
-use crate::{
-    CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
-    MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
-};
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
-use rustc_error_messages::FluentValue;
-use rustc_lint_defs::{Applicability, LintExpectationId};
-use rustc_macros::{Decodable, Encodable};
-use rustc_span::source_map::Spanned;
-use rustc_span::symbol::Symbol;
-use rustc_span::{Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::fmt::{self, Debug};
 use std::hash::{Hash, Hasher};
@@ -18,8 +5,22 @@ use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 use std::panic;
 use std::thread::panicking;
+
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_error_messages::{fluent_value_from_str_list_sep_by_and, FluentValue};
+use rustc_lint_defs::{Applicability, LintExpectationId};
+use rustc_macros::{Decodable, Encodable};
+use rustc_span::source_map::Spanned;
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
 use tracing::debug;
 
+use crate::snippet::Style;
+use crate::{
+    CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
+    MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
+};
+
 /// Error type for `DiagInner`'s `suggestions` field, indicating that
 /// `.disable_suggestions()` was called on the `DiagInner`.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
@@ -740,6 +741,16 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         self
     }
 
+    #[rustc_lint_diagnostics]
+    pub fn highlighted_span_note(
+        &mut self,
+        span: impl Into<MultiSpan>,
+        msg: Vec<StringPart>,
+    ) -> &mut Self {
+        self.sub_with_highlights(Level::Note, msg, span.into());
+        self
+    }
+
     /// This is like [`Diag::note()`], but it's only printed once.
     #[rustc_lint_diagnostics]
     pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
@@ -814,6 +825,17 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         self
     }
 
+    /// Add a help message attached to this diagnostic with a customizable highlighted message.
+    #[rustc_lint_diagnostics]
+    pub fn highlighted_span_help(
+        &mut self,
+        span: impl Into<MultiSpan>,
+        msg: Vec<StringPart>,
+    ) -> &mut Self {
+        self.sub_with_highlights(Level::Help, msg, span.into());
+        self
+    }
+
     /// Prints the span with some help above it.
     /// This is like [`Diag::help()`], but it gets its own span.
     #[rustc_lint_diagnostics]
@@ -898,8 +920,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
-        suggestion.sort_unstable();
-        suggestion.dedup_by(|(s1, m1), (s2, m2)| s1.source_equal(*s2) && m1 == m2);
+        let mut seen = crate::FxHashSet::default();
+        suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
 
         let parts = suggestion
             .into_iter()
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index e6ca1bf7bc4..9e3bc3e60b1 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,12 +1,11 @@
-use crate::diagnostic::DiagLocation;
-use crate::{fluent_generated as fluent, DiagCtxtHandle, Subdiagnostic};
-use crate::{
-    Diag, DiagArgValue, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
-    SubdiagMessageOp,
-};
-use rustc_ast as ast;
+use std::backtrace::Backtrace;
+use std::borrow::Cow;
+use std::fmt;
+use std::num::ParseIntError;
+use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
+
 use rustc_ast_pretty::pprust;
-use rustc_hir as hir;
 use rustc_macros::Subdiagnostic;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
@@ -14,12 +13,13 @@ use rustc_span::Span;
 use rustc_target::abi::TargetDataLayoutErrors;
 use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
 use rustc_type_ir::{ClosureKind, FloatTy};
-use std::backtrace::Backtrace;
-use std::borrow::Cow;
-use std::fmt;
-use std::num::ParseIntError;
-use std::path::{Path, PathBuf};
-use std::process::ExitStatus;
+use {rustc_ast as ast, rustc_hir as hir};
+
+use crate::diagnostic::DiagLocation;
+use crate::{
+    fluent_generated as fluent, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee,
+    ErrCode, IntoDiagArg, Level, SubdiagMessageOp, Subdiagnostic,
+};
 
 pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
 
@@ -66,6 +66,7 @@ macro_rules! into_diag_arg_for_number {
             impl IntoDiagArg for $ty {
                 fn into_diag_arg(self) -> DiagArgValue {
                     // Convert to a string if it won't fit into `Number`.
+                    #[allow(irrefutable_let_patterns)]
                     if let Ok(n) = TryInto::<i32>::try_into(self) {
                         DiagArgValue::Number(n)
                     } else {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 58220c65490..9ce5d77ef6c 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -7,35 +7,35 @@
 //!
 //! The output types are defined in `rustc_session::config::ErrorOutputType`.
 
+use std::borrow::Cow;
+use std::cmp::{max, min, Reverse};
+use std::error::Report;
+use std::io::prelude::*;
+use std::io::{self, IsTerminal};
+use std::iter;
+use std::path::Path;
+
+use derive_setters::Setters;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
+use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, Lrc};
+use rustc_error_messages::{FluentArgs, SpanLabel};
+use rustc_lint_defs::pluralize;
+use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
 use rustc_span::{char_width, FileLines, FileName, SourceFile, Span};
+use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
+use tracing::{debug, instrument, trace, warn};
 
+use crate::diagnostic::DiagLocation;
 use crate::snippet::{
     Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
 };
 use crate::styled_buffer::StyledBuffer;
 use crate::translation::{to_fluent_args, Translate};
 use crate::{
-    diagnostic::DiagLocation, CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode,
-    FluentBundle, LazyFallbackBundle, Level, MultiSpan, Subdiag, SubstitutionHighlight,
-    SuggestionStyle, TerminalUrl,
+    CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle,
+    Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
 };
-use derive_setters::Setters;
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
-use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, Lrc};
-use rustc_error_messages::{FluentArgs, SpanLabel};
-use rustc_lint_defs::pluralize;
-use rustc_span::hygiene::{ExpnKind, MacroKind};
-use std::borrow::Cow;
-use std::cmp::{max, min, Reverse};
-use std::error::Report;
-use std::io::prelude::*;
-use std::io::{self, IsTerminal};
-use std::iter;
-use std::path::Path;
-use termcolor::{Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream};
-use termcolor::{Color, WriteColor};
-use tracing::{debug, instrument, trace, warn};
 
 /// Default column width, used in tests and when terminal dimensions cannot be determined.
 const DEFAULT_COLUMN_WIDTH: usize = 140;
@@ -43,19 +43,14 @@ const DEFAULT_COLUMN_WIDTH: usize = 140;
 /// Describes the way the content of the `rendered` field of the json output is generated
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum HumanReadableErrorType {
-    Default(ColorConfig),
-    AnnotateSnippet(ColorConfig),
-    Short(ColorConfig),
+    Default,
+    AnnotateSnippet,
+    Short,
 }
 
 impl HumanReadableErrorType {
-    /// Returns a (`short`, `color`) tuple
-    pub fn unzip(self) -> (bool, ColorConfig) {
-        match self {
-            HumanReadableErrorType::Default(cc) => (false, cc),
-            HumanReadableErrorType::Short(cc) => (true, cc),
-            HumanReadableErrorType::AnnotateSnippet(cc) => (false, cc),
-        }
+    pub fn short(&self) -> bool {
+        *self == HumanReadableErrorType::Short
     }
 }
 
@@ -231,17 +226,17 @@ pub trait Emitter: Translate {
     ) {
         if let Some((sugg, rest)) = suggestions.split_first() {
             let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
-            if rest.is_empty() &&
+            if rest.is_empty()
                // ^ if there is only one suggestion
                // don't display multi-suggestions as labels
-               sugg.substitutions.len() == 1 &&
+               && let [substitution] = sugg.substitutions.as_slice()
                // don't display multipart suggestions as labels
-               sugg.substitutions[0].parts.len() == 1 &&
+               && let [part] = substitution.parts.as_slice()
                // don't display long messages as labels
-               msg.split_whitespace().count() < 10 &&
+               && msg.split_whitespace().count() < 10
                // don't display multiline suggestions as labels
-               !sugg.substitutions[0].parts[0].snippet.contains('\n') &&
-               ![
+               && !part.snippet.contains('\n')
+               && ![
                     // when this style is set we want the suggestion to be a message, not inline
                     SuggestionStyle::HideCodeAlways,
                     // trivial suggestion for tooling's sake, never shown
@@ -250,8 +245,8 @@ pub trait Emitter: Translate {
                     SuggestionStyle::ShowAlways,
                ].contains(&sugg.style)
             {
-                let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
-                let msg = if substitution.is_empty() || sugg.style.hide_inline() {
+                let snippet = part.snippet.trim();
+                let msg = if snippet.is_empty() || sugg.style.hide_inline() {
                     // This substitution is only removal OR we explicitly don't want to show the
                     // code inline (`hide_inline`). Therefore, we don't show the substitution.
                     format!("help: {msg}")
@@ -260,19 +255,18 @@ pub trait Emitter: Translate {
                     format!(
                         "help: {}{}: `{}`",
                         msg,
-                        if self.source_map().is_some_and(|sm| is_case_difference(
-                            sm,
-                            substitution,
-                            sugg.substitutions[0].parts[0].span,
-                        )) {
+                        if self
+                            .source_map()
+                            .is_some_and(|sm| is_case_difference(sm, snippet, part.span,))
+                        {
                             " (notice the capitalization)"
                         } else {
                             ""
                         },
-                        substitution,
+                        snippet,
                     )
                 };
-                primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
+                primary_span.push_span_label(part.span, msg);
 
                 // We return only the modified primary_span
                 suggestions.clear();
@@ -1346,10 +1340,11 @@ impl HumanEmitter {
                 buffer.append(0, ": ", header_style);
                 label_width += 2;
             }
-            for (text, _) in msgs.iter() {
+            let mut line = 0;
+            for (text, style) in msgs.iter() {
                 let text = self.translate_message(text, args).map_err(Report::new).unwrap();
                 // Account for newlines to align output to its label.
-                for (line, text) in normalize_whitespace(&text).lines().enumerate() {
+                for text in normalize_whitespace(&text).lines() {
                     buffer.append(
                         line,
                         &format!(
@@ -1357,8 +1352,38 @@ impl HumanEmitter {
                             if line == 0 { String::new() } else { " ".repeat(label_width) },
                             text
                         ),
-                        header_style,
+                        match style {
+                            Style::Highlight => *style,
+                            _ => header_style,
+                        },
                     );
+                    line += 1;
+                }
+                // We add lines above, but if the last line has no explicit newline (which would
+                // yield an empty line), then we revert one line up to continue with the next
+                // styled text chunk on the same line as the last one from the prior one. Otherwise
+                // every `text` would appear on their own line (because even though they didn't end
+                // in '\n', they advanced `line` by one).
+                if line > 0 {
+                    line -= 1;
+                }
+            }
+            if self.short_message {
+                let labels = msp
+                    .span_labels()
+                    .into_iter()
+                    .filter_map(|label| match label.label {
+                        Some(msg) if label.is_primary => {
+                            let text = self.translate_message(&msg, args).ok()?;
+                            if !text.trim().is_empty() { Some(text.to_string()) } else { None }
+                        }
+                        _ => None,
+                    })
+                    .collect::<Vec<_>>()
+                    .join(", ");
+                if !labels.is_empty() {
+                    buffer.append(line, ": ", Style::NoStyle);
+                    buffer.append(line, &labels, Style::NoStyle);
                 }
             }
         }
@@ -1767,7 +1792,10 @@ impl HumanEmitter {
         debug!(?suggestions);
 
         if suggestions.is_empty() {
-            // Suggestions coming from macros can have malformed spans. This is a heavy handed
+            // Here we check if there are suggestions that have actual code changes. We sometimes
+            // suggest the same code that is already there, instead of changing how we produce the
+            // suggestions and filtering there, we just don't emit the suggestion.
+            // Suggestions coming from macros can also have malformed spans. This is a heavy handed
             // approach to avoid ICEs by ignoring the suggestion outright.
             return Ok(());
         }
@@ -2046,7 +2074,9 @@ impl HumanEmitter {
                     assert!(underline_start >= 0 && underline_end >= 0);
                     let padding: usize = max_line_num_len + 3;
                     for p in underline_start..underline_end {
-                        if let DisplaySuggestion::Underline = show_code_change {
+                        if let DisplaySuggestion::Underline = show_code_change
+                            && is_different(sm, &part.snippet, part.span)
+                        {
                             // If this is a replacement, underline with `~`, if this is an addition
                             // underline with `+`.
                             buffer.putc(
@@ -2560,21 +2590,10 @@ fn num_decimal_digits(num: usize) -> usize {
 // We replace some characters so the CLI output is always consistent and underlines aligned.
 // Keep the following list in sync with `rustc_span::char_width`.
 const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
-    ('\t', "    "),    // We do our own tab replacement
-    ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
-    ('\u{202A}', "�"), // The following unicode text flow control characters are inconsistently
-    ('\u{202B}', "�"), // supported across CLIs and can cause confusion due to the bytes on disk
-    ('\u{202D}', "�"), // not corresponding to the visible source code, so we replace them always.
-    ('\u{202E}', "�"),
-    ('\u{2066}', "�"),
-    ('\u{2067}', "�"),
-    ('\u{2068}', "�"),
-    ('\u{202C}', "�"),
-    ('\u{2069}', "�"),
     // In terminals without Unicode support the following will be garbled, but in *all* terminals
     // the underlying codepoint will be as well. We could gate this replacement behind a "unicode
     // support" gate.
-    ('\u{0000}', "␀"),
+    ('\0', "␀"),
     ('\u{0001}', "␁"),
     ('\u{0002}', "␂"),
     ('\u{0003}', "␃"),
@@ -2583,11 +2602,12 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
     ('\u{0006}', "␆"),
     ('\u{0007}', "␇"),
     ('\u{0008}', "␈"),
-    ('\u{000B}', "␋"),
-    ('\u{000C}', "␌"),
-    ('\u{000D}', "␍"),
-    ('\u{000E}', "␎"),
-    ('\u{000F}', "␏"),
+    ('\t', "    "), // We do our own tab replacement
+    ('\u{000b}', "␋"),
+    ('\u{000c}', "␌"),
+    ('\u{000d}', "␍"),
+    ('\u{000e}', "␎"),
+    ('\u{000f}', "␏"),
     ('\u{0010}', "␐"),
     ('\u{0011}', "␑"),
     ('\u{0012}', "␒"),
@@ -2598,21 +2618,47 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
     ('\u{0017}', "␗"),
     ('\u{0018}', "␘"),
     ('\u{0019}', "␙"),
-    ('\u{001A}', "␚"),
-    ('\u{001B}', "␛"),
-    ('\u{001C}', "␜"),
-    ('\u{001D}', "␝"),
-    ('\u{001E}', "␞"),
-    ('\u{001F}', "␟"),
-    ('\u{007F}', "␡"),
+    ('\u{001a}', "␚"),
+    ('\u{001b}', "␛"),
+    ('\u{001c}', "␜"),
+    ('\u{001d}', "␝"),
+    ('\u{001e}', "␞"),
+    ('\u{001f}', "␟"),
+    ('\u{007f}', "␡"),
+    ('\u{200d}', ""), // Replace ZWJ for consistent terminal output of grapheme clusters.
+    ('\u{202a}', "�"), // The following unicode text flow control characters are inconsistently
+    ('\u{202b}', "�"), // supported across CLIs and can cause confusion due to the bytes on disk
+    ('\u{202c}', "�"), // not corresponding to the visible source code, so we replace them always.
+    ('\u{202d}', "�"),
+    ('\u{202e}', "�"),
+    ('\u{2066}', "�"),
+    ('\u{2067}', "�"),
+    ('\u{2068}', "�"),
+    ('\u{2069}', "�"),
 ];
 
-fn normalize_whitespace(str: &str) -> String {
-    let mut s = str.to_string();
-    for (c, replacement) in OUTPUT_REPLACEMENTS {
-        s = s.replace(*c, replacement);
+fn normalize_whitespace(s: &str) -> String {
+    const {
+        let mut i = 1;
+        while i < OUTPUT_REPLACEMENTS.len() {
+            assert!(
+                OUTPUT_REPLACEMENTS[i - 1].0 < OUTPUT_REPLACEMENTS[i].0,
+                "The OUTPUT_REPLACEMENTS array must be sorted (for binary search to work) \
+                and must contain no duplicate entries"
+            );
+            i += 1;
+        }
     }
-    s
+    // Scan the input string for a character in the ordered table above.
+    // If it's present, replace it with its alternative string (it can be more than 1 char!).
+    // Otherwise, retain the input char.
+    s.chars().fold(String::with_capacity(s.len()), |mut s, c| {
+        match OUTPUT_REPLACEMENTS.binary_search_by_key(&c, |(k, _)| *k) {
+            Ok(i) => s.push_str(OUTPUT_REPLACEMENTS[i].1),
+            _ => s.push(c),
+        }
+        s
+    })
 }
 
 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
@@ -2824,6 +2870,18 @@ impl Style {
     }
 }
 
+/// Whether the original and suggested code are the same.
+pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
+    let found = match sm.span_to_snippet(sp) {
+        Ok(snippet) => snippet,
+        Err(e) => {
+            warn!(error = ?e, "Invalid span {:?}", sp);
+            return true;
+        }
+    };
+    found != suggested
+}
+
 /// Whether the original and suggested code are visually similar enough to warrant extra wording.
 pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
     // FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
diff --git a/compiler/rustc_errors/src/error.rs b/compiler/rustc_errors/src/error.rs
index ca818a4d832..462467d9fa0 100644
--- a/compiler/rustc_errors/src/error.rs
+++ b/compiler/rustc_errors/src/error.rs
@@ -1,11 +1,10 @@
-use rustc_error_messages::{
-    fluent_bundle::resolver::errors::{ReferenceKind, ResolverError},
-    FluentArgs, FluentError,
-};
 use std::borrow::Cow;
 use std::error::Error;
 use std::fmt;
 
+use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError};
+use rustc_error_messages::{FluentArgs, FluentError};
+
 #[derive(Debug)]
 pub enum TranslateError<'args> {
     One {
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 764134d5335..32e59f9ab03 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -9,16 +9,12 @@
 
 // FIXME: spec the JSON output properly.
 
-use crate::emitter::{
-    should_show_source_code, ColorConfig, Destination, Emitter, HumanEmitter,
-    HumanReadableErrorType,
-};
-use crate::registry::Registry;
-use crate::translation::{to_fluent_args, Translate};
-use crate::{
-    diagnostic::IsLint, CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel,
-    Subdiag, TerminalUrl,
-};
+use std::error::Report;
+use std::io::{self, Write};
+use std::path::Path;
+use std::sync::{Arc, Mutex};
+use std::vec;
+
 use derive_setters::Setters;
 use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
 use rustc_error_messages::FluentArgs;
@@ -27,13 +23,19 @@ use rustc_span::hygiene::ExpnData;
 use rustc_span::source_map::SourceMap;
 use rustc_span::Span;
 use serde::Serialize;
-use std::error::Report;
-use std::io::{self, Write};
-use std::path::Path;
-use std::sync::{Arc, Mutex};
-use std::vec;
 use termcolor::{ColorSpec, WriteColor};
 
+use crate::diagnostic::IsLint;
+use crate::emitter::{
+    should_show_source_code, ColorConfig, Destination, Emitter, HumanEmitter,
+    HumanReadableErrorType,
+};
+use crate::registry::Registry;
+use crate::translation::{to_fluent_args, Translate};
+use crate::{
+    CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, TerminalUrl,
+};
+
 #[cfg(test)]
 mod tests;
 
@@ -53,6 +55,7 @@ pub struct JsonEmitter {
     ignored_directories_in_source_blocks: Vec<String>,
     #[setters(skip)]
     json_rendered: HumanReadableErrorType,
+    color_config: ColorConfig,
     diagnostic_width: Option<usize>,
     macro_backtrace: bool,
     track_diagnostics: bool,
@@ -66,6 +69,7 @@ impl JsonEmitter {
         fallback_bundle: LazyFallbackBundle,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        color_config: ColorConfig,
     ) -> JsonEmitter {
         JsonEmitter {
             dst: IntoDynSyncSend(dst),
@@ -77,6 +81,7 @@ impl JsonEmitter {
             ui_testing: false,
             ignored_directories_in_source_blocks: Vec::new(),
             json_rendered,
+            color_config,
             diagnostic_width: None,
             macro_backtrace: false,
             track_diagnostics: false,
@@ -171,7 +176,7 @@ impl Emitter for JsonEmitter {
     }
 
     fn should_show_explain(&self) -> bool {
-        !matches!(self.json_rendered, HumanReadableErrorType::Short(_))
+        !self.json_rendered.short()
     }
 }
 
@@ -351,8 +356,8 @@ impl Diagnostic {
 
         let buf = BufWriter::default();
         let mut dst: Destination = Box::new(buf.clone());
-        let (short, color_config) = je.json_rendered.unzip();
-        match color_config {
+        let short = je.json_rendered.short();
+        match je.color_config {
             ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)),
             ColorConfig::Never => {}
         }
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index e4b29fc9103..6af376d7afd 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -1,13 +1,12 @@
-use super::*;
+use std::str;
 
-use crate::DiagCtxt;
 use rustc_span::source_map::FilePathMapping;
 use rustc_span::BytePos;
-
-use std::str;
-
 use serde::Deserialize;
 
+use super::*;
+use crate::DiagCtxt;
+
 #[derive(Deserialize, Debug, PartialEq, Eq)]
 struct TestData {
     spans: Vec<SpanTestData>,
@@ -51,7 +50,8 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
             sm,
             fallback_bundle,
             true, // pretty
-            HumanReadableErrorType::Short(ColorConfig::Never),
+            HumanReadableErrorType::Short,
+            ColorConfig::Never,
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 2a850d9303c..3bc03a1e516 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -10,6 +10,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(array_windows)]
+#![feature(assert_matches)]
 #![feature(associated_type_defaults)]
 #![feature(box_into_inner)]
 #![feature(box_patterns)]
@@ -28,6 +29,18 @@
 
 extern crate self as rustc_errors;
 
+use std::assert_matches::assert_matches;
+use std::backtrace::{Backtrace, BacktraceStatus};
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::error::Report;
+use std::hash::Hash;
+use std::io::Write;
+use std::num::NonZero;
+use std::ops::DerefMut;
+use std::path::{Path, PathBuf};
+use std::{fmt, panic};
+
 pub use codes::*;
 pub use diagnostic::{
     BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
@@ -39,42 +52,28 @@ pub use diagnostic_impls::{
     IndicateAnonymousLifetime, SingleLabelManySpans,
 };
 pub use emitter::ColorConfig;
+use emitter::{is_case_difference, is_different, DynEmitter, Emitter};
+use registry::Registry;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
+use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_data_structures::AtomicRef;
 pub use rustc_error_messages::{
     fallback_fluent_bundle, fluent_bundle, DiagMessage, FluentBundle, LanguageIdentifier,
     LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
 };
+use rustc_lint_defs::LintExpectationId;
 pub use rustc_lint_defs::{pluralize, Applicability};
+use rustc_macros::{Decodable, Encodable};
 pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
+use rustc_span::source_map::SourceMap;
 pub use rustc_span::ErrorGuaranteed;
+use rustc_span::{Loc, Span, DUMMY_SP};
 pub use snippet::Style;
-
 // Used by external projects such as `rust-gpu`.
 // See https://github.com/rust-lang/rust/pull/115393.
 pub use termcolor::{Color, ColorSpec, WriteColor};
-
-use emitter::{is_case_difference, DynEmitter, Emitter};
-use registry::Registry;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
-use rustc_data_structures::sync::{Lock, Lrc};
-use rustc_data_structures::AtomicRef;
-use rustc_lint_defs::LintExpectationId;
-use rustc_macros::{Decodable, Encodable};
-use rustc_span::source_map::SourceMap;
-use rustc_span::{Loc, Span, DUMMY_SP};
-use std::backtrace::{Backtrace, BacktraceStatus};
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::error::Report;
-use std::fmt;
-use std::hash::Hash;
-use std::io::Write;
-use std::num::NonZero;
-use std::ops::DerefMut;
-use std::panic;
-use std::path::{Path, PathBuf};
 use tracing::debug;
-
 use Level::*;
 
 pub mod annotate_snippet_emitter_writer;
@@ -360,10 +359,16 @@ impl CodeSuggestion {
                             _ => 1,
                         })
                         .sum();
-                    line_highlight.push(SubstitutionHighlight {
-                        start: (cur_lo.col.0 as isize + acc) as usize,
-                        end: (cur_lo.col.0 as isize + acc + len) as usize,
-                    });
+                    if !is_different(sm, &part.snippet, part.span) {
+                        // Account for cases where we are suggesting the same code that's already
+                        // there. This shouldn't happen often, but in some cases for multipart
+                        // suggestions it's much easier to handle it here than in the origin.
+                    } else {
+                        line_highlight.push(SubstitutionHighlight {
+                            start: (cur_lo.col.0 as isize + acc) as usize,
+                            end: (cur_lo.col.0 as isize + acc + len) as usize,
+                        });
+                    }
                     buf.push_str(&part.snippet);
                     let cur_hi = sm.lookup_char_pos(part.span.hi());
                     // Account for the difference between the width of the current code and the
@@ -395,7 +400,11 @@ impl CodeSuggestion {
                 while buf.ends_with('\n') {
                     buf.pop();
                 }
-                Some((buf, substitution.parts, highlights, only_capitalization))
+                if highlights.iter().all(|parts| parts.is_empty()) {
+                    None
+                } else {
+                    Some((buf, substitution.parts, highlights, only_capitalization))
+                }
             })
             .collect()
     }
@@ -1483,7 +1492,7 @@ impl DiagCtxtInner {
             // Future breakages aren't emitted if they're `Level::Allow` or
             // `Level::Expect`, but they still need to be constructed and
             // stashed below, so they'll trigger the must_produce_diag check.
-            assert!(matches!(diagnostic.level, Error | Warning | Allow | Expect(_)));
+            assert_matches!(diagnostic.level, Error | Warning | Allow | Expect(_));
             self.future_breakage_diagnostics.push(diagnostic.clone());
         }
 
@@ -2017,11 +2026,11 @@ pub fn a_or_an(s: &str) -> &'static str {
 ///
 /// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
 pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
-    match v.len() {
-        0 => "".to_string(),
-        1 => v[0].to_string(),
-        2 => format!("{} and {}", v[0], v[1]),
-        _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
+    match v {
+        [] => "".to_string(),
+        [a] => a.to_string(),
+        [a, b] => format!("{a} and {b}"),
+        [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
     }
 }
 
diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs
index 0aeb511214b..915542c9092 100644
--- a/compiler/rustc_errors/src/lock.rs
+++ b/compiler/rustc_errors/src/lock.rs
@@ -16,10 +16,10 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     use std::ffi::CString;
     use std::io;
 
-    use windows::{
-        core::PCSTR,
-        Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0},
-        Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject, INFINITE},
+    use windows::core::PCSTR;
+    use windows::Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0};
+    use windows::Win32::System::Threading::{
+        CreateMutexA, ReleaseMutex, WaitForSingleObject, INFINITE,
     };
 
     struct Handle(HANDLE);
diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs
index 69e7120e714..c44f136120a 100644
--- a/compiler/rustc_errors/src/markdown/parse.rs
+++ b/compiler/rustc_errors/src/markdown/parse.rs
@@ -1,6 +1,7 @@
-use crate::markdown::{MdStream, MdTree};
 use std::{iter, mem, str};
 
+use crate::markdown::{MdStream, MdTree};
+
 /// Short aliases that we can use in match patterns. If an end pattern is not
 /// included, this type may be variable
 const ANC_E: &[u8] = b">";
diff --git a/compiler/rustc_errors/src/markdown/tests/parse.rs b/compiler/rustc_errors/src/markdown/tests/parse.rs
index e2e3f354ff6..bfcb3de16fa 100644
--- a/compiler/rustc_errors/src/markdown/tests/parse.rs
+++ b/compiler/rustc_errors/src/markdown/tests/parse.rs
@@ -1,6 +1,7 @@
-use super::*;
 use ParseOpt as PO;
 
+use super::*;
+
 #[test]
 fn test_parse_simple() {
     let buf = "**abcd** rest";
diff --git a/compiler/rustc_errors/src/markdown/tests/term.rs b/compiler/rustc_errors/src/markdown/tests/term.rs
index bab47dcc175..e025870f055 100644
--- a/compiler/rustc_errors/src/markdown/tests/term.rs
+++ b/compiler/rustc_errors/src/markdown/tests/term.rs
@@ -1,5 +1,6 @@
 use std::io::BufWriter;
 use std::path::PathBuf;
+
 use termcolor::{BufferWriter, ColorChoice};
 
 use super::*;
diff --git a/compiler/rustc_errors/src/registry.rs b/compiler/rustc_errors/src/registry.rs
index 8834d04d971..baca7700d90 100644
--- a/compiler/rustc_errors/src/registry.rs
+++ b/compiler/rustc_errors/src/registry.rs
@@ -1,6 +1,7 @@
-use crate::ErrCode;
 use rustc_data_structures::fx::FxHashMap;
 
+use crate::ErrCode;
+
 #[derive(Debug)]
 pub struct InvalidErrorCode;
 
diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs
index d6119fb41d2..50abf8a49c2 100644
--- a/compiler/rustc_errors/src/snippet.rs
+++ b/compiler/rustc_errors/src/snippet.rs
@@ -1,8 +1,9 @@
 // Code for annotating snippets.
 
-use crate::{Level, Loc};
 use rustc_macros::{Decodable, Encodable};
 
+use crate::{Level, Loc};
+
 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
 pub struct Line {
     pub line_index: usize,
diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs
index 50d58aec36a..bfe4c9f2a3a 100644
--- a/compiler/rustc_errors/src/tests.rs
+++ b/compiler/rustc_errors/src/tests.rs
@@ -1,11 +1,11 @@
+use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
+use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError};
+use rustc_error_messages::{langid, DiagMessage};
+
 use crate::error::{TranslateError, TranslateErrorKind};
 use crate::fluent_bundle::*;
 use crate::translation::Translate;
 use crate::FluentBundle;
-use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
-use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError};
-use rustc_error_messages::langid;
-use rustc_error_messages::DiagMessage;
 
 struct Dummy {
     bundle: FluentBundle,
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index 445e9b4fd6e..a44e794ee12 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -1,13 +1,15 @@
-use crate::error::{TranslateError, TranslateErrorKind};
-use crate::snippet::Style;
-use crate::{DiagArg, DiagMessage, FluentBundle};
-use rustc_data_structures::sync::Lrc;
-pub use rustc_error_messages::FluentArgs;
 use std::borrow::Cow;
 use std::env;
 use std::error::Report;
+
+use rustc_data_structures::sync::Lrc;
+pub use rustc_error_messages::FluentArgs;
 use tracing::{debug, trace};
 
+use crate::error::{TranslateError, TranslateErrorKind};
+use crate::snippet::Style;
+use crate::{DiagArg, DiagMessage, FluentBundle};
+
 /// Convert diagnostic arguments (a rustc internal type that exists to implement
 /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
 ///
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 18d95a398fd..766d96e268f 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -129,6 +129,9 @@ expand_module_multiple_candidates =
 expand_must_repeat_once =
     this must repeat at least once
 
+expand_non_inline_modules_in_proc_macro_input_are_unstable =
+    non-inline modules in proc macro input are unstable
+
 expand_not_a_meta_item =
     not a meta item
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index b439ec74ffa..8f9104135cd 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,7 +1,7 @@
-use crate::base::ast::NestedMetaItem;
-use crate::errors;
-use crate::expand::{self, AstFragment, Invocation};
-use crate::module::DirOwnership;
+use std::default::Default;
+use std::iter;
+use std::path::{Path, PathBuf};
+use std::rc::Rc;
 
 use rustc_ast::attr::MarkedAttrs;
 use rustc_ast::ptr::P;
@@ -15,9 +15,11 @@ use rustc_data_structures::sync::{self, Lrc};
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
 use rustc_feature::Features;
 use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
-use rustc_parse::{parser::Parser, MACRO_ARGUMENTS};
+use rustc_parse::parser::Parser;
+use rustc_parse::MACRO_ARGUMENTS;
 use rustc_session::config::CollapseMacroDebuginfo;
-use rustc_session::{parse::ParseSess, Limit, Session};
+use rustc_session::parse::ParseSess;
+use rustc_session::{Limit, Session};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
@@ -25,12 +27,13 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{FileName, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
-use std::default::Default;
-use std::iter;
-use std::path::{Path, PathBuf};
-use std::rc::Rc;
 use thin_vec::ThinVec;
 
+use crate::base::ast::NestedMetaItem;
+use crate::errors;
+use crate::expand::{self, AstFragment, Invocation};
+use crate::module::DirOwnership;
+
 // When adding new variants, make sure to
 // adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector`
 // to use `assign_id!`
@@ -1303,12 +1306,12 @@ pub fn parse_macro_name_and_helper_attrs(
     // that it's of the form `#[proc_macro_derive(Foo)]` or
     // `#[proc_macro_derive(Foo, attributes(A, ..))]`
     let list = attr.meta_item_list()?;
-    if list.len() != 1 && list.len() != 2 {
+    let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
         dcx.emit_err(errors::AttrNoArguments { span: attr.span });
         return None;
-    }
-    let Some(trait_attr) = list[0].meta_item() else {
-        dcx.emit_err(errors::NotAMetaItem { span: list[0].span() });
+    };
+    let Some(trait_attr) = trait_attr.meta_item() else {
+        dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() });
         return None;
     };
     let trait_ident = match trait_attr.ident() {
@@ -1395,8 +1398,6 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) {
         };
 
         if crate_matches {
-            // FIXME: make this translatable
-            #[allow(rustc::untranslatable_diagnostic)]
             sess.dcx().emit_fatal(errors::ProcMacroBackCompat {
                 crate_name: "rental".to_string(),
                 fixed_version: "0.5.6".to_string(),
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 37dfd830512..8ecdb551342 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -1,12 +1,15 @@
-use crate::base::ExtCtxt;
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp};
-use rustc_ast::{attr, token, util::literal};
+use rustc_ast::util::literal;
+use rustc_ast::{
+    self as ast, attr, token, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp,
+};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use thin_vec::{thin_vec, ThinVec};
 
+use crate::base::ExtCtxt;
+
 impl<'a> ExtCtxt<'a> {
     pub fn path(&self, span: Span, strs: Vec<Ident>) -> ast::Path {
         self.path_all(span, false, strs, vec![])
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 6c02c237115..f6bf9f5e89f 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -1,19 +1,16 @@
 //! Conditional compilation stripping.
 
-use crate::errors::{
-    FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute,
-    MalformedFeatureAttributeHelp, RemoveExprNotSupported,
-};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, Spacing};
-use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree};
-use rustc_ast::NodeId;
-use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
+use rustc_ast::tokenstream::{
+    AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
+};
+use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
 use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
-use rustc_feature::Features;
-use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
+use rustc_feature::{
+    AttributeSafety, Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES,
+};
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::validate_attr;
 use rustc_session::parse::feature_err;
@@ -23,6 +20,11 @@ use rustc_span::Span;
 use thin_vec::ThinVec;
 use tracing::instrument;
 
+use crate::errors::{
+    FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute,
+    MalformedFeatureAttributeHelp, RemoveExprNotSupported,
+};
+
 /// A folder that strips out items that do not belong in the current configuration.
 pub struct StripUnconfigured<'a> {
     pub sess: &'a Session,
@@ -117,6 +119,12 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
             // Otherwise, the feature is unknown. Record it as a lib feature.
             // It will be checked later.
             features.set_declared_lib_feature(name, mi.span());
+
+            // Similar to above, detect internal lib features to suppress
+            // the ICE message that asks for a report.
+            if features.internal(name) && ![sym::core, sym::alloc, sym::std].contains(&crate_name) {
+                sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
+            }
         }
     }
 
@@ -257,6 +265,13 @@ impl<'a> StripUnconfigured<'a> {
     /// 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, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
+        validate_attr::check_attribute_safety(
+            self.features.unwrap_or(&Features::default()),
+            &self.sess.psess,
+            AttributeSafety::Normal,
+            &cfg_attr,
+        );
+
         let Some((cfg_predicate, expanded_attrs)) =
             rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
         else {
@@ -379,6 +394,13 @@ impl<'a> StripUnconfigured<'a> {
                 return (true, None);
             }
         };
+
+        validate_attr::deny_builtin_meta_unsafety(
+            self.features.unwrap_or(&Features::default()),
+            &self.sess.psess,
+            &meta_item,
+        );
+
         (
             parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| {
                 attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features)
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 6f1a0f16c49..c30a9b0c357 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -1,10 +1,11 @@
+use std::borrow::Cow;
+
 use rustc_ast::ast;
 use rustc_errors::codes::*;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::Limit;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
 use rustc_span::{Span, Symbol};
-use std::borrow::Cow;
 
 #[derive(Diagnostic)]
 #[diag(expand_expr_repeat_no_syntax_vars)]
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3c43d47292f..37679e17b90 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,13 +1,7 @@
-use crate::base::*;
-use crate::config::StripUnconfigured;
-use crate::errors::{
-    EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse,
-    RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,
-    WrongFragmentKind,
-};
-use crate::mbe::diagnostics::annotate_err_with_kind;
-use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
-use crate::placeholders::{placeholder, PlaceholderExpander};
+use std::ops::Deref;
+use std::path::PathBuf;
+use std::rc::Rc;
+use std::{iter, mem};
 
 use rustc_ast as ast;
 use rustc_ast::mut_visit::*;
@@ -15,10 +9,11 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, try_visit, walk_list, AssocCtxt, Visitor, VisitorResult};
-use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind};
-use rustc_ast::{ForeignItemKind, HasAttrs, HasNodeId};
-use rustc_ast::{Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind};
-use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind};
+use rustc_ast::{
+    AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind,
+    HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem,
+    NodeId, PatKind, StmtKind, TyKind,
+};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_data_structures::sync::Lrc;
@@ -35,12 +30,19 @@ use rustc_session::{Limit, Session};
 use rustc_span::hygiene::SyntaxContext;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{ErrorGuaranteed, FileName, LocalExpnId, Span};
-
 use smallvec::SmallVec;
-use std::ops::Deref;
-use std::path::PathBuf;
-use std::rc::Rc;
-use std::{iter, mem};
+
+use crate::base::*;
+use crate::config::StripUnconfigured;
+use crate::errors::{
+    EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse,
+    RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,
+    WrongFragmentKind,
+};
+use crate::fluent_generated;
+use crate::mbe::diagnostics::annotate_err_with_kind;
+use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
+use crate::placeholders::{placeholder, PlaceholderExpander};
 
 macro_rules! ast_fragments {
     (
@@ -881,7 +883,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
 
         impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
-            #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
                     ItemKind::Mod(_, mod_kind)
@@ -891,7 +892,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             self.sess,
                             sym::proc_macro_hygiene,
                             item.span,
-                            "non-inline modules in proc macro input are unstable",
+                            fluent_generated::expand_non_inline_modules_in_proc_macro_input_are_unstable,
                         )
                         .emit();
                     }
@@ -1875,7 +1876,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
         let features = self.cx.ecfg.features;
         let mut attrs = attrs.iter().peekable();
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 2df8b8f00f8..628c6bfeb79 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -1,36 +1,34 @@
-use crate::base::{DummyResult, ExtCtxt, MacResult};
-use crate::expand::{parse_ast_fragment, AstFragmentKind};
-use crate::mbe::{
-    macro_parser::{MatcherLoc, NamedParseResult, ParseResult::*, TtParser},
-    macro_rules::{try_match_macro, Tracker},
-};
+use std::borrow::Cow;
+
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, Diag, DiagMessage};
+use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
 use rustc_macros::Subdiagnostic;
 use rustc_parse::parser::{Parser, Recovery};
+use rustc_session::parse::ParseSess;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Ident;
 use rustc_span::{ErrorGuaranteed, Span};
-use std::borrow::Cow;
 use tracing::debug;
 
 use super::macro_rules::{parser_from_cx, NoopTracker};
+use crate::expand::{parse_ast_fragment, AstFragmentKind};
+use crate::mbe::macro_parser::ParseResult::*;
+use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser};
+use crate::mbe::macro_rules::{try_match_macro, Tracker};
 
-pub(super) fn failed_to_match_macro<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
+pub(super) fn failed_to_match_macro(
+    psess: &ParseSess,
     sp: Span,
     def_span: Span,
     name: Ident,
     arg: TokenStream,
     lhses: &[Vec<MatcherLoc>],
-) -> Box<dyn MacResult + 'cx> {
-    let psess = &cx.sess.psess;
-
+) -> (Span, ErrorGuaranteed) {
     // An error occurred, try the expansion again, tracking the expansion closely for better
     // diagnostics.
-    let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
+    let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
 
     let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut tracker);
 
@@ -38,7 +36,7 @@ pub(super) fn failed_to_match_macro<'cx>(
         // Nonterminal parser recovery might turn failed matches into successful ones,
         // but for that it must have emitted an error already
         assert!(
-            tracker.cx.dcx().has_errors().is_some(),
+            tracker.dcx.has_errors().is_some(),
             "Macro matching returned a success on the second try"
         );
     }
@@ -50,15 +48,15 @@ pub(super) fn failed_to_match_macro<'cx>(
 
     let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
     else {
-        return DummyResult::any(sp, cx.dcx().span_delayed_bug(sp, "failed to match a macro"));
+        return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
     };
 
     let span = token.span.substitute_dummy(sp);
 
-    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token, None));
+    let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None));
     err.span_label(span, label);
-    if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
-        err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
+    if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
+        err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro");
     }
 
     annotate_doc_comment(&mut err, psess.source_map(), span);
@@ -76,7 +74,7 @@ pub(super) fn failed_to_match_macro<'cx>(
         err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
         err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
 
-        if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
+        if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
             err.help("try using `:tt` instead in the macro definition");
         }
     }
@@ -104,18 +102,17 @@ pub(super) fn failed_to_match_macro<'cx>(
         }
     }
     let guar = err.emit();
-    cx.trace_macros_diag();
-    DummyResult::any(sp, guar)
+    (sp, guar)
 }
 
 /// The tracker used for the slow error path that collects useful info for diagnostics.
-struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
-    cx: &'a mut ExtCtxt<'cx>,
+struct CollectTrackerAndEmitter<'dcx, 'matcher> {
+    dcx: DiagCtxtHandle<'dcx>,
     remaining_matcher: Option<&'matcher MatcherLoc>,
     /// Which arm's failure should we report? (the one furthest along)
     best_failure: Option<BestFailure>,
     root_span: Span,
-    result: Option<Box<dyn MacResult + 'cx>>,
+    result: Option<(Span, ErrorGuaranteed)>,
 }
 
 struct BestFailure {
@@ -131,7 +128,7 @@ impl BestFailure {
     }
 }
 
-impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
+impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'matcher> {
     type Failure = (Token, u32, &'static str);
 
     fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure {
@@ -151,7 +148,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
             Success(_) => {
                 // Nonterminal parser recovery might turn failed matches into successful ones,
                 // but for that it must have emitted an error already
-                self.cx.dcx().span_delayed_bug(
+                self.dcx.span_delayed_bug(
                     self.root_span,
                     "should not collect detailed info for successful macro match",
                 );
@@ -177,10 +174,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
             }
             Error(err_sp, msg) => {
                 let span = err_sp.substitute_dummy(self.root_span);
-                let guar = self.cx.dcx().span_err(span, msg.clone());
-                self.result = Some(DummyResult::any(span, guar));
+                let guar = self.dcx.span_err(span, msg.clone());
+                self.result = Some((span, guar));
             }
-            ErrorReported(guar) => self.result = Some(DummyResult::any(self.root_span, *guar)),
+            ErrorReported(guar) => self.result = Some((self.root_span, *guar)),
         }
     }
 
@@ -193,9 +190,9 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
     }
 }
 
-impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
-    fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
-        Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None }
+impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> {
+    fn new(dcx: DiagCtxtHandle<'dcx>, root_span: Span) -> Self {
+        Self { dcx, remaining_matcher: None, best_failure: None, root_span, result: None }
     }
 }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 161e27fe02c..68eeba6f415 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -105,8 +105,7 @@
 //! stored when entering a macro definition starting from the state in which the meta-variable is
 //! bound.
 
-use crate::errors;
-use crate::mbe::{KleeneToken, TokenTree};
+use std::iter;
 
 use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
@@ -116,14 +115,13 @@ use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
 use rustc_session::parse::ParseSess;
 use rustc_span::edition::Edition;
-use rustc_span::symbol::kw;
-use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span};
-
+use rustc_span::symbol::{kw, MacroRulesNormalizedIdent};
+use rustc_span::{ErrorGuaranteed, Span};
 use smallvec::SmallVec;
 
-use std::iter;
-
 use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021;
+use crate::errors;
+use crate::mbe::{KleeneToken, TokenTree};
 
 /// Stack represented as linked list.
 ///
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 99a9d4f8912..e5b9c627429 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -70,10 +70,10 @@
 //! eof: [a $( a )* a b ·]
 //! ```
 
-pub(crate) use NamedMatch::*;
-pub(crate) use ParseResult::*;
-
-use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
+use std::borrow::Cow;
+use std::collections::hash_map::Entry::{Occupied, Vacant};
+use std::fmt::Display;
+use std::rc::Rc;
 
 use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
 use rustc_ast_pretty::pprust;
@@ -81,13 +81,13 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_lint_defs::pluralize;
 use rustc_parse::parser::{ParseNtResult, Parser};
-use rustc_span::symbol::Ident;
-use rustc_span::symbol::MacroRulesNormalizedIdent;
+use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
 use rustc_span::Span;
-use std::borrow::Cow;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-use std::fmt::Display;
-use std::rc::Rc;
+pub(crate) use NamedMatch::*;
+pub(crate) use ParseResult::*;
+
+use crate::mbe::macro_rules::Tracker;
+use crate::mbe::{KleeneOp, TokenTree};
 
 /// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from)
 /// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching.
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 88ec3d83664..6f177107e70 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1,18 +1,12 @@
-use crate::base::{DummyResult, SyntaxExtension, SyntaxExtensionKind};
-use crate::base::{ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, TTMacroExpander};
-use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
-use crate::mbe;
-use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
-use crate::mbe::macro_check;
-use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
-use crate::mbe::macro_parser::{MatcherLoc, NamedMatch::*};
-use crate::mbe::transcribe::transcribe;
+use std::borrow::Cow;
+use std::collections::hash_map::Entry;
+use std::{mem, slice};
 
 use ast::token::IdentIsRaw;
 use rustc_ast as ast;
-use rustc_ast::token::{
-    self, Delimiter, NonterminalKind, NtPatKind::*, Token, TokenKind, TokenKind::*,
-};
+use rustc_ast::token::NtPatKind::*;
+use rustc_ast::token::TokenKind::*;
+use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
@@ -33,12 +27,19 @@ use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::Span;
 use tracing::{debug, instrument, trace, trace_span};
 
-use std::borrow::Cow;
-use std::collections::hash_map::Entry;
-use std::{mem, slice};
-
 use super::diagnostics;
 use super::macro_parser::{NamedMatches, NamedParseResult};
+use crate::base::{
+    DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
+    SyntaxExtensionKind, TTMacroExpander,
+};
+use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
+use crate::mbe;
+use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
+use crate::mbe::macro_check;
+use crate::mbe::macro_parser::NamedMatch::*;
+use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
+use crate::mbe::transcribe::transcribe;
 
 pub(crate) struct ParserAnyMacro<'a> {
     parser: Parser<'a>,
@@ -267,7 +268,10 @@ fn expand_macro<'cx>(
         }
         Err(CanRetry::Yes) => {
             // Retry and emit a better error.
-            diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
+            let (span, guar) =
+                diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, lhses);
+            cx.trace_macros_diag();
+            DummyResult::any(span, guar)
         }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 57b6947316d..e5a1c6c7899 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -1,18 +1,18 @@
-use crate::errors;
-use crate::mbe::macro_parser::count_metavar_decls;
-use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
-
-use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, NtExprKind::*, Token};
+use rustc_ast::token::NtExprKind::*;
+use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token};
 use rustc_ast::{tokenstream, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_feature::Features;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
-use rustc_span::symbol::{kw, sym, Ident};
-
 use rustc_span::edition::Edition;
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 
+use crate::errors;
+use crate::mbe::macro_parser::count_metavar_decls;
+use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
+
 const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
                                         `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
                                         `literal`, `path`, `meta`, `tt`, `item` and `vis`";
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 0da542d379d..b06910595bb 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -1,26 +1,27 @@
-use crate::errors::{
-    CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
-    NoSyntaxVarsExprRepeat, VarStillRepeating,
-};
-use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
-use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR};
-use crate::mbe::{self, KleeneOp, MetaVarExpr};
+use std::mem;
+
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
-use rustc_ast::token::{IdentIsRaw, Lit, LitKind};
+use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_ast::ExprKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult};
 use rustc_parse::lexer::nfc_normalize;
 use rustc_parse::parser::ParseNtResult;
-use rustc_session::parse::ParseSess;
-use rustc_session::parse::SymbolGallery;
+use rustc_session::parse::{ParseSess, SymbolGallery};
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext};
 use smallvec::{smallvec, SmallVec};
-use std::mem;
+
+use crate::errors::{
+    CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
+    NoSyntaxVarsExprRepeat, VarStillRepeating,
+};
+use crate::mbe::macro_parser::NamedMatch;
+use crate::mbe::macro_parser::NamedMatch::*;
+use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR};
+use crate::mbe::{self, KleeneOp, MetaVarExpr};
 
 // A Marker adds the given mark to the syntax context.
 struct Marker(LocalExpnId, Transparency, FxHashMap<SyntaxContext, SyntaxContext>);
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 506bd445be3..13348376851 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -1,20 +1,21 @@
-use crate::base::ModuleData;
-use crate::errors::{
-    ModuleCircular, ModuleFileNotFound, ModuleInBlock, ModuleInBlockName, ModuleMultipleCandidates,
-};
+use std::iter::once;
+use std::path::{self, Path, PathBuf};
+
 use rustc_ast::ptr::P;
 use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans};
 use rustc_errors::{Diag, ErrorGuaranteed};
-use rustc_parse::validate_attr;
-use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
+use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, validate_attr};
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
-use std::iter::once;
-use std::path::{self, Path, PathBuf};
 use thin_vec::ThinVec;
 
+use crate::base::ModuleData;
+use crate::errors::{
+    ModuleCircular, ModuleFileNotFound, ModuleInBlock, ModuleInBlockName, ModuleMultipleCandidates,
+};
+
 #[derive(Copy, Clone)]
 pub enum DirOwnership {
     Owned {
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 3fa909877cc..1e455d465e4 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -1,14 +1,16 @@
-use crate::expand::{AstFragment, AstFragmentKind};
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
 use rustc_ast::token::Delimiter;
-use rustc_ast::{self as ast, visit::AssocCtxt};
+use rustc_ast::visit::AssocCtxt;
+use rustc_ast::{self as ast};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::symbol::Ident;
 use rustc_span::DUMMY_SP;
 use smallvec::{smallvec, SmallVec};
 use thin_vec::ThinVec;
 
+use crate::expand::{AstFragment, AstFragmentKind};
+
 pub(crate) fn placeholder(
     kind: AstFragmentKind,
     id: ast::NodeId,
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 96145affe0a..24f631ed5dc 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -1,7 +1,3 @@
-use crate::base::{self, *};
-use crate::errors;
-use crate::proc_macro_server;
-
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::tokenstream::TokenStream;
@@ -11,6 +7,9 @@ use rustc_session::config::ProcMacroExecutionStrategy;
 use rustc_span::profiling::SpannedEventArgRecorder;
 use rustc_span::Span;
 
+use crate::base::{self, *};
+use crate::{errors, proc_macro_server};
+
 struct MessagePipe<T> {
     tx: std::sync::mpsc::SyncSender<T>,
     rx: std::sync::mpsc::Receiver<T>,
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 5508358f53b..1438d1ad11f 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,4 +1,5 @@
-use crate::base::ExtCtxt;
+use std::ops::{Bound, Range};
+
 use ast::token::IdentIsRaw;
 use pm::bridge::{
     server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
@@ -20,7 +21,8 @@ use rustc_span::def_id::CrateNum;
 use rustc_span::symbol::{self, sym, Symbol};
 use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
 use smallvec::{smallvec, SmallVec};
-use std::ops::{Bound, Range};
+
+use crate::base::ExtCtxt;
 
 trait FromInternal<T> {
     fn from_internal(x: T) -> Self;
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e671c768239..44286cfeeef 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -1,8 +1,9 @@
 //! List of the accepted feature gates.
 
-use super::{to_nonzero, Feature};
 use rustc_span::symbol::sym;
 
+use super::{to_nonzero, Feature};
+
 macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr),
@@ -85,7 +86,7 @@ declare_features! (
     /// Allows `c"foo"` literals.
     (accepted, c_str_literals, "1.77.0", Some(105723)),
     /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries and treat `extern "C" fn` as nounwind.
-    (accepted, c_unwind, "CURRENT_RUSTC_VERSION", Some(74990)),
+    (accepted, c_unwind, "1.81.0", Some(74990)),
     /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
     (accepted, cfg_attr_multi, "1.33.0", Some(54881)),
     /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
@@ -237,7 +238,7 @@ declare_features! (
     /// Allows `let...else` statements.
     (accepted, let_else, "1.65.0", Some(87335)),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
-    (accepted, lint_reasons, "CURRENT_RUSTC_VERSION", Some(54503)),
+    (accepted, lint_reasons, "1.81.0", Some(54503)),
     /// Allows `break {expr}` with a value inside `loop`s.
     (accepted, loop_break_value, "1.19.0", Some(37339)),
     /// Allows use of `?` as the Kleene "at most one" operator in macros.
@@ -266,6 +267,8 @@ declare_features! (
     (accepted, min_const_generics, "1.51.0", Some(74878)),
     /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
     (accepted, min_const_unsafe_fn, "1.33.0", Some(55607)),
+    /// Allows exhaustive pattern matching on uninhabited types when matched by value.
+    (accepted, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)),
     /// Allows using `Self` and associated types in struct expressions and patterns.
     (accepted, more_struct_aliases, "1.16.0", Some(37544)),
     /// Allows using the MOVBE target feature.
@@ -291,6 +294,8 @@ declare_features! (
     (accepted, non_exhaustive, "1.40.0", Some(44109)),
     /// Allows `foo.rs` as an alternative to `foo/mod.rs`.
     (accepted, non_modrs_mods, "1.30.0", Some(44660)),
+    /// Allows using multiple nested field accesses in offset_of!
+    (accepted, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)),
     /// Allows the use of or-patterns (e.g., `0 | 1`).
     (accepted, or_patterns, "1.53.0", Some(54883)),
     /// Allows using `+bundle,+whole-archive` link modifiers with native libs.
@@ -387,6 +392,8 @@ declare_features! (
     (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208)),
     /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
     (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668)),
+    /// Allows unsafe on extern declarations and safety qualifiers over internal items.
+    (accepted, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
     /// Allows importing and reexporting macros with `use`,
     /// enables macro modularization in general.
     (accepted, use_extern_macros, "1.30.0", Some(35896)),
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 7b27049a579..72ea55d5999 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1,16 +1,15 @@
 //! Built-in attributes and `cfg` flag gating.
 
+use std::sync::LazyLock;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{sym, Symbol};
 use AttributeDuplicates::*;
 use AttributeGate::*;
 use AttributeType::*;
 
 use crate::{Features, Stability};
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{sym, Symbol};
-
-use std::sync::LazyLock;
-
 type GateFn = fn(&Features) -> bool;
 
 macro_rules! cfg_fn {
@@ -704,21 +703,21 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator),
     ),
     gated!(
-        panic_runtime, Normal, template!(Word), WarnFollowing,
+        panic_runtime, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, experimental!(panic_runtime)
     ),
     gated!(
-        needs_panic_runtime, Normal, template!(Word), WarnFollowing,
+        needs_panic_runtime, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, experimental!(needs_panic_runtime)
     ),
     gated!(
-        compiler_builtins, Normal, template!(Word), WarnFollowing,
+        compiler_builtins, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No,
         "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
         which contains compiler-rt intrinsics and will never be stable",
     ),
     gated!(
-        profiler_runtime, Normal, template!(Word), WarnFollowing,
+        profiler_runtime, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No,
         "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
         which contains the profiler runtime and will never be stable",
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index e9d3ce0a074..dcc1c3202ea 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -25,9 +25,10 @@ mod unstable;
 #[cfg(test)]
 mod tests;
 
-use rustc_span::symbol::Symbol;
 use std::num::NonZero;
 
+use rustc_span::symbol::Symbol;
+
 #[derive(Debug, Clone)]
 pub struct Feature {
     pub name: Symbol,
@@ -126,11 +127,10 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
 }
 
 pub use accepted::ACCEPTED_FEATURES;
-pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
     deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
-    is_valid_for_get_attr, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
-    BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+    is_valid_for_get_attr, AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate,
+    AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::REMOVED_FEATURES;
 pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 80a108d2fc8..b7f0ed5afce 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -1,8 +1,9 @@
 //! List of the removed feature gates.
 
-use super::{to_nonzero, Feature};
 use rustc_span::symbol::sym;
 
+use super::{to_nonzero, Feature};
+
 pub struct RemovedFeature {
     pub feature: Feature,
     pub reason: Option<&'static str>,
@@ -81,6 +82,9 @@ declare_features! (
     /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
     (removed, custom_derive, "1.32.0", Some(29644),
      Some("subsumed by `#[proc_macro_derive]`")),
+    /// Allows default type parameters to influence type inference.
+    (removed, default_type_parameter_fallback, "CURRENT_RUSTC_VERSION", Some(27336),
+     Some("never properly implemented; requires significant design work")),
     /// Allows using `#[doc(keyword = "...")]`.
     (removed, doc_keyword, "1.28.0", Some(51315),
      Some("merged into `#![feature(rustdoc_internals)]`")),
@@ -222,7 +226,7 @@ declare_features! (
     (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),
+    (removed, wasm_abi, "1.81.0", 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 d3d07181096..47810bc9165 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -1,11 +1,11 @@
 //! List of the unstable feature gates.
 
-use super::{to_nonzero, Feature};
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
+use super::{to_nonzero, Feature};
+
 pub struct UnstableFeature {
     pub feature: Feature,
     pub set_enabled: fn(&mut Features),
@@ -431,8 +431,6 @@ declare_features! (
     (unstable, custom_test_frameworks, "1.30.0", Some(50297)),
     /// Allows declarative macros 2.0 (`macro`).
     (unstable, decl_macro, "1.17.0", Some(39412)),
-    /// Allows default type parameters to influence type inference.
-    (unstable, default_type_parameter_fallback, "1.3.0", Some(27336)),
     /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait
     (unstable, deprecated_safe, "1.61.0", Some(94978)),
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
@@ -518,12 +516,9 @@ declare_features! (
     /// Give access to additional metadata about declarative macro meta-variables.
     (unstable, macro_metavar_expr, "1.61.0", Some(83527)),
     /// Provides a way to concatenate identifiers using metavariable expressions.
-    (unstable, macro_metavar_expr_concat, "CURRENT_RUSTC_VERSION", Some(124225)),
+    (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (unstable, marker_trait_attr, "1.30.0", Some(29864)),
-    /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are
-    /// unambiguously sound.
-    (unstable, min_exhaustive_patterns, "1.77.0", Some(119612)),
     /// A minimal, sound subset of specialization intended to be used by the
     /// standard library until the soundness issues with specialization
     /// are fixed.
@@ -560,14 +555,12 @@ declare_features! (
     (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)),
     /// Allows using enums in offset_of!
     (unstable, offset_of_enum, "1.75.0", Some(120141)),
-    /// Allows using multiple nested field accesses in offset_of!
-    (unstable, offset_of_nested, "1.77.0", Some(120140)),
     /// Allows using fields with slice type in offset_of!
-    (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)),
+    (unstable, offset_of_slice, "1.81.0", Some(126151)),
     /// Allows using `#[optimize(X)]`.
     (unstable, optimize_attribute, "1.34.0", Some(54882)),
     /// Allows specifying nop padding on functions for dynamic patching.
-    (unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(123115)),
+    (unstable, patchable_function_entry, "1.81.0", Some(123115)),
     /// Allows postfix match `expr.match { ... }`
     (unstable, postfix_match, "1.79.0", Some(121618)),
     /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
@@ -579,7 +572,7 @@ declare_features! (
     /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
     (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
     /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
-    (incomplete, ref_pat_eat_one_layer_2024_structural, "CURRENT_RUSTC_VERSION", Some(123076)),
+    (incomplete, ref_pat_eat_one_layer_2024_structural, "1.81.0", Some(123076)),
     /// Allows using the `#[register_tool]` attribute.
     (unstable, register_tool, "1.41.0", Some(66079)),
     /// Allows the `#[repr(i128)]` attribute for enums.
@@ -593,6 +586,8 @@ declare_features! (
     (incomplete, return_type_notation, "1.70.0", Some(109417)),
     /// Allows `extern "rust-cold"`.
     (unstable, rust_cold_cc, "1.63.0", Some(97544)),
+    /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
+    (unstable, sha512_sm_x86, "CURRENT_RUSTC_VERSION", Some(126624)),
     /// Shortern the tail expression lifetime
     (unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
@@ -631,8 +626,6 @@ declare_features! (
     (incomplete, unnamed_fields, "1.74.0", Some(49804)),
     /// Allows unsafe attributes.
     (unstable, unsafe_attributes, "1.80.0", Some(123757)),
-    /// Allows unsafe on extern declarations and safety qualifiers over internal items.
-    (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
     /// Allows const generic parameters to be defined with types that
     /// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
     (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)),
@@ -645,9 +638,9 @@ declare_features! (
     /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
     (unstable, used_with_arg, "1.60.0", Some(93798)),
     /// Allows use of x86 `AMX` target-feature attributes and intrinsics
-    (unstable, x86_amx_intrinsics, "CURRENT_RUSTC_VERSION", Some(126622)),
+    (unstable, x86_amx_intrinsics, "1.81.0", Some(126622)),
     /// Allows use of the `xop` target-feature
-    (unstable, xop_target_feature, "CURRENT_RUSTC_VERSION", Some(127208)),
+    (unstable, xop_target_feature, "1.81.0", Some(127208)),
     /// Allows `do yeet` expressions
     (unstable, yeet_expr, "1.62.0", Some(96373)),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 68fdabd3529..23795a96b92 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -1,20 +1,16 @@
+use std::collections::{HashMap, HashSet};
+use std::fs::read_to_string;
+use std::path::{Path, PathBuf};
+
 use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 use fluent_bundle::{FluentBundle, FluentError, FluentResource};
-use fluent_syntax::{
-    ast::{
-        Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern,
-        PatternElement,
-    },
-    parser::ParserError,
+use fluent_syntax::ast::{
+    Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement,
 };
+use fluent_syntax::parser::ParserError;
 use proc_macro::{Diagnostic, Level, Span};
 use proc_macro2::TokenStream;
 use quote::quote;
-use std::{
-    collections::{HashMap, HashSet},
-    fs::read_to_string,
-    path::{Path, PathBuf},
-};
 use syn::{parse_macro_input, Ident, LitStr};
 use unic_langid::langid;
 
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index d376c24cb58..91eae98071a 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -1,7 +1,6 @@
 use std::ffi::CString;
-use std::fs;
-use std::io;
 use std::path::{absolute, Path, PathBuf};
+use std::{fs, io};
 
 // Unfortunately, on windows, it looks like msvcrt.dll is silently translating
 // verbatim paths under the hood to non-verbatim paths! This manifests itself as
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index c0fe98254f0..c8f8fd5be02 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -279,12 +279,12 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
-use LabelText::*;
-
 use std::borrow::Cow;
 use std::io;
 use std::io::prelude::*;
 
+use LabelText::*;
+
 /// The text for a graphviz label on a node or edge.
 pub enum LabelText<'a> {
     /// This kind of label preserves the text directly as is.
diff --git a/compiler/rustc_graphviz/src/tests.rs b/compiler/rustc_graphviz/src/tests.rs
index 154bae4cb05..01e6cb9a3da 100644
--- a/compiler/rustc_graphviz/src/tests.rs
+++ b/compiler/rustc_graphviz/src/tests.rs
@@ -1,9 +1,11 @@
-use super::LabelText::{self, EscStr, HtmlStr, LabelStr};
-use super::{render, Edges, GraphWalk, Id, Labeller, Nodes, Style};
 use std::io;
 use std::io::prelude::*;
+
 use NodeLabels::*;
 
+use super::LabelText::{self, EscStr, HtmlStr, LabelStr};
+use super::{render, Edges, GraphWalk, Id, Labeller, Nodes, Style};
+
 /// each node is an index in a vector in the graph.
 type Node = usize;
 struct Edge {
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index b1854923247..59204d79928 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -1,5 +1,5 @@
-use crate::definitions::DefPathData;
-use crate::hir;
+use std::array::IntoIter;
+use std::fmt::Debug;
 
 use rustc_ast as ast;
 use rustc_ast::NodeId;
@@ -11,8 +11,8 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::kw;
 use rustc_span::Symbol;
 
-use std::array::IntoIter;
-use std::fmt::Debug;
+use crate::definitions::DefPathData;
+use crate::hir;
 
 /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct.
 #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 5c86135ec8d..8c2be2152ea 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -4,18 +4,20 @@
 //! There are also some rather random cases (like const initializer
 //! expressions) that are mostly just leftovers.
 
-pub use crate::def_id::DefPathHash;
-use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use crate::def_path_hash_map::DefPathHashMap;
+use std::fmt::{self, Write};
+use std::hash::Hash;
+
 use rustc_data_structures::stable_hasher::{Hash64, StableHasher};
 use rustc_data_structures::unord::UnordMap;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::symbol::{kw, sym, Symbol};
-use std::fmt::{self, Write};
-use std::hash::Hash;
 use tracing::{debug, instrument};
 
+pub use crate::def_id::DefPathHash;
+use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_path_hash_map::DefPathHashMap;
+
 /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
 /// stores the `DefIndex` of its parent.
diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs
index d4d09f9a4e0..23a83a5011b 100644
--- a/compiler/rustc_hir/src/diagnostic_items.rs
+++ b/compiler/rustc_hir/src/diagnostic_items.rs
@@ -1,9 +1,10 @@
-use crate::def_id::DefId;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_span::def_id::DefIdMap;
 use rustc_span::Symbol;
 
+use crate::def_id::DefId;
+
 #[derive(Debug, Default)]
 pub struct DiagnosticItems {
     pub id_to_name: DefIdMap<Symbol>,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 8c8f760bc41..33e8432596b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,29 +1,35 @@
-use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::{DefId, LocalDefIdMap};
-pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
-use crate::intravisit::FnKind;
-use crate::LangItem;
+use std::fmt;
+
 use rustc_ast as ast;
 use rustc_ast::util::parser::ExprPrecedence;
-use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
-pub use rustc_ast::{BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy};
-pub use rustc_ast::{ImplPolarity, IsAuto, Movability, Mutability, UnOp};
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::{
+    Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitKind,
+    TraitObjectSyntax, UintTy,
+};
+pub use rustc_ast::{
+    BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability,
+    Mutability, UnOp,
+};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::ErrorGuaranteed;
-use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, ErrorGuaranteed, Span, DUMMY_SP};
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use rustc_target::spec::abi::Abi;
 use smallvec::SmallVec;
-use std::fmt;
 use tracing::debug;
 
+use crate::def::{CtorKind, DefKind, Res};
+use crate::def_id::{DefId, LocalDefIdMap};
+pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
+use crate::intravisit::FnKind;
+use crate::LangItem;
+
 #[derive(Debug, Copy, Clone, HashStable_Generic)]
 pub struct Lifetime {
     pub hir_id: HirId,
@@ -2946,6 +2952,17 @@ pub struct FnDecl<'hir> {
     pub lifetime_elision_allowed: bool,
 }
 
+impl<'hir> FnDecl<'hir> {
+    pub fn opt_delegation_sig_id(&self) -> Option<DefId> {
+        if let FnRetTy::Return(ty) = self.output
+            && let TyKind::InferDelegation(sig_id, _) = ty.kind
+        {
+            return Some(sig_id);
+        }
+        None
+    }
+}
+
 /// Represents what type of implicit self a function has, if any.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum ImplicitSelfKind {
@@ -3683,6 +3700,11 @@ impl<'hir> OwnerNode<'hir> {
         }
     }
 
+    /// Check if node is an impl block.
+    pub fn is_impl_block(&self) -> bool {
+        matches!(self, OwnerNode::Item(Item { kind: ItemKind::Impl(_), .. }))
+    }
+
     expect_methods_self! {
         expect_item,         &'hir Item<'hir>,        OwnerNode::Item(n),        n;
         expect_foreign_item, &'hir ForeignItem<'hir>, OwnerNode::ForeignItem(n), n;
@@ -4008,8 +4030,9 @@ impl<'hir> Node<'hir> {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Block<'_>, 48);
     static_assert_size!(Body<'_>, 24);
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index c0ca1a8017e..f2142359935 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,8 +1,11 @@
-use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
+use std::fmt::{self, Debug};
+
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt::{self, Debug};
+use rustc_span::def_id::DefPathHash;
+use rustc_span::HashStableContext;
+
+use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
 pub struct OwnerId {
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 696f548f1ba..dd501f8417e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -64,13 +64,14 @@
 //! This order consistency is required in a few places in rustc, for
 //! example coroutine inference, and possibly also HIR borrowck.
 
-use crate::hir::*;
 use rustc_ast::visit::{try_visit, visit_opt, walk_list, VisitorResult};
 use rustc_ast::{Attribute, Label};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
+use crate::hir::*;
+
 pub trait IntoVisitor<'hir> {
     type Visitor: Visitor<'hir>;
     fn into_visitor(&self) -> Self::Visitor;
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 1821387e85f..e7398fd2226 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -7,9 +7,6 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
-use crate::def_id::DefId;
-use crate::{MethodKind, Target};
-
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -17,6 +14,9 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
+use crate::def_id::DefId;
+use crate::{MethodKind, Target};
+
 /// All of the lang items, defined or not.
 /// Defined lang items can come from the current crate or its dependencies.
 #[derive(HashStable_Generic, Debug)]
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 9991b02b1e1..73d1ea40707 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -1,10 +1,11 @@
-use crate::def::{CtorOf, DefKind, Res};
-use crate::def_id::{DefId, DefIdSet};
-use crate::hir::{self, BindingMode, ByRef, HirId, PatKind};
+use std::iter::Enumerate;
+
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-use std::iter::Enumerate;
+use crate::def::{CtorOf, DefKind, Res};
+use crate::def_id::{DefId, DefIdSet};
+use crate::hir::{self, BindingMode, ByRef, HirId, PatKind};
 
 pub struct EnumerateAndAdjust<I> {
     enumerate: Enumerate<I>,
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index baa1635f731..fe169e989ec 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,10 +1,10 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_span::def_id::DefPathHash;
 
 use crate::hir::{
     AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
 };
 use crate::hir_id::{HirId, ItemLocalId};
-use rustc_span::def_id::DefPathHash;
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index e448d29e55f..f43008eda11 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -4,11 +4,10 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::hir;
-use crate::{Item, ItemKind, TraitItem, TraitItemKind};
+use std::fmt::{self, Display};
 
 use crate::def::DefKind;
-use std::fmt::{self, Display};
+use crate::{hir, Item, ItemKind, TraitItem, TraitItemKind};
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum GenericParamKind {
diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs
index 571923b5462..16b3c4a9ab6 100644
--- a/compiler/rustc_hir/src/tests.rs
+++ b/compiler/rustc_hir/src/tests.rs
@@ -1,9 +1,10 @@
-use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
 use rustc_data_structures::stable_hasher::Hash64;
 use rustc_span::def_id::{DefPathHash, StableCrateId};
 use rustc_span::edition::Edition;
 use rustc_span::{create_session_globals_then, Symbol};
 
+use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
+
 #[test]
 fn def_path_hash_depends_on_crate_id() {
     // This test makes sure that *both* halves of a DefPathHash depend on
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index 0cc50c6dd85..ca133c5965d 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -1,9 +1,9 @@
 //! Validity checking for weak lang items
 
-use crate::LangItem;
-
 use rustc_span::symbol::{sym, Symbol};
 
+use crate::LangItem;
+
 macro_rules! weak_lang_items {
     ($($item:ident, $sym:ident;)*) => {
         pub static WEAK_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*];
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 367f6e17e7f..bde94be6f51 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -341,8 +341,7 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
 
 hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
 
-hir_analysis_not_supported_delegation =
-    {$descr} is not supported yet
+hir_analysis_not_supported_delegation = {$descr}
     .label = callee defined here
 
 hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 2bf14a2461f..53c8586b52a 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -1,15 +1,14 @@
-use crate::errors::AutoDerefReachedRecursionLimit;
-use crate::traits;
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Limit;
-use rustc_span::def_id::LocalDefId;
-use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_span::Span;
 use rustc_trait_selection::traits::ObligationCtxt;
 
+use crate::errors::AutoDerefReachedRecursionLimit;
+use crate::traits;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+
 #[derive(Copy, Clone, Debug)]
 pub enum AutoderefKind {
     /// A true pointer type, such as `&T` and `*mut T`.
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 27db5418165..2e778fd3759 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,12 +1,9 @@
-use crate::check::intrinsicck::InlineAsmCtxt;
+use std::cell::LazyCell;
+use std::ops::ControlFlow;
 
-use super::compare_impl_item::check_type_bounds;
-use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
-use super::*;
-use rustc_attr as attr;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_errors::{codes::*, MultiSpan};
-use rustc_hir as hir;
+use rustc_errors::codes::*;
+use rustc_errors::MultiSpan;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::Node;
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
@@ -19,9 +16,9 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
-use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::{
-    AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt,
 };
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_target::abi::FieldIdx;
@@ -30,9 +27,11 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
+use {rustc_attr as attr, rustc_hir as hir};
 
-use std::cell::LazyCell;
-use std::ops::ControlFlow;
+use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty};
+use super::*;
+use crate::check::intrinsicck::InlineAsmCtxt;
 
 pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
     match tcx.sess.target.is_abi_supported(abi) {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index c99f13468e2..35577613800 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1,24 +1,24 @@
-use super::potentially_plural_count;
-use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
 use core::ops::ControlFlow;
+use std::borrow::Cow;
+use std::iter;
+
 use hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
+use rustc_errors::codes::*;
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit;
-use rustc_hir::{GenericParamKind, ImplItemKind};
+use rustc_hir::{intravisit, GenericParamKind, ImplItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
-    self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder,
+    TypeSuperFoldable, TypeVisitableExt, Upcast,
 };
-use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -28,8 +28,9 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
 };
-use std::borrow::Cow;
-use std::iter;
+
+use super::potentially_plural_count;
+use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
 
 mod refine;
 
@@ -1116,7 +1117,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
             .dcx()
             .create_err(LifetimesOrBoundsMismatchOnTrait {
                 span,
-                item_kind: assoc_item_kind_str(&impl_m),
+                item_kind: impl_m.descr(),
                 ident: impl_m.ident(tcx),
                 generics_span,
                 bounds_span,
@@ -1293,7 +1294,7 @@ fn compare_number_of_generics<'tcx>(
         ("const", trait_own_counts.consts, impl_own_counts.consts),
     ];
 
-    let item_kind = assoc_item_kind_str(&impl_);
+    let item_kind = impl_.descr();
 
     let mut err_occurred = None;
     for (kind, trait_count, impl_count) in matchings {
@@ -1675,7 +1676,7 @@ fn compare_generic_param_kinds<'tcx>(
                 param_impl_span,
                 E0053,
                 "{} `{}` has an incompatible generic parameter for trait `{}`",
-                assoc_item_kind_str(&impl_item),
+                impl_item.descr(),
                 trait_item.name,
                 &tcx.def_path_str(tcx.parent(trait_item.def_id))
             );
@@ -2248,14 +2249,6 @@ fn param_env_with_gat_bounds<'tcx>(
     ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
 }
 
-fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
-    match impl_item.kind {
-        ty::AssocKind::Const => "const",
-        ty::AssocKind::Fn => "method",
-        ty::AssocKind::Type => "type",
-    }
-}
-
 /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
 /// and extract a better error if so.
 fn try_report_async_mismatch<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index ad3324f79e2..80daaa60324 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -1,7 +1,8 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
 use rustc_middle::span_bug;
 use rustc_middle::traits::{ObligationCause, Reveal};
@@ -10,9 +11,8 @@ use rustc_middle::ty::{
 };
 use rustc_span::Span;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::{
-    elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt,
-};
+use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
+use rustc_trait_selection::traits::{elaborate, normalize_param_env_or_error, ObligationCtxt};
 
 /// Check that an implementation does not refine an RPITIT from a trait method signature.
 pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 06ec01484a4..d173915e480 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -3,13 +3,13 @@
 // We don't do any drop checking during hir typeck.
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, ErrorGuaranteed};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::util::CheckRegions;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_middle::ty::{GenericArgsRef, Ty};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index e4d4b7df24e..1f724580564 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -1,3 +1,5 @@
+use std::ops::Not;
+
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -5,13 +7,12 @@ use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
-use std::ops::Not;
-
 use super::check_function_signature;
 use crate::errors;
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 6282499883b..4b45ced30c5 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -1,13 +1,8 @@
 //! Type-checking for the rust-intrinsic and platform-intrinsic
 //! intrinsics that the compiler exposes.
 
-use crate::check::check_function_signature;
-use crate::errors::{
-    UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
-    WrongNumberOfGenericArgumentsToIntrinsic,
-};
-
-use rustc_errors::{codes::*, struct_span_code_err, DiagMessage};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, DiagMessage};
 use rustc_hir as hir;
 use rustc_middle::bug;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
@@ -17,6 +12,12 @@ use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
+use crate::check::check_function_signature;
+use crate::errors::{
+    UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
+    WrongNumberOfGenericArgumentsToIntrinsic,
+};
+
 fn equate_intrinsic_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     span: Span,
@@ -119,6 +120,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::type_id
         | sym::likely
         | sym::unlikely
+        | sym::select_unpredictable
         | sym::ptr_guaranteed_cmp
         | sym::minnumf16
         | sym::minnumf32
@@ -487,6 +489,7 @@ pub fn check_intrinsic_type(
             sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit),
             sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
             sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
+            sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)),
 
             sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
             sym::write_via_move => {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 2e965c59ebb..79ecdee4486 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,8 +1,10 @@
+use std::assert_matches::debug_assert_matches;
+
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
+use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Symbol;
@@ -455,32 +457,22 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         );
                     }
                 }
-                // No special checking is needed for these:
-                // - Typeck has checked that Const operands are integers.
-                // - AST lowering guarantees that SymStatic points to a static.
-                hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {}
-                // Check that sym actually points to a function. Later passes
-                // depend on this.
+                // Typeck has checked that Const operands are integers.
+                hir::InlineAsmOperand::Const { anon_const } => {
+                    debug_assert_matches!(
+                        self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
+                        ty::Error(_) | ty::Int(_) | ty::Uint(_)
+                    );
+                }
+                // Typeck has checked that SymFn refers to a function.
                 hir::InlineAsmOperand::SymFn { anon_const } => {
-                    let ty = self.tcx.type_of(anon_const.def_id).instantiate_identity();
-                    match ty.kind() {
-                        ty::Never | ty::Error(_) => {}
-                        ty::FnDef(..) => {}
-                        _ => {
-                            self.tcx
-                                .dcx()
-                                .struct_span_err(*op_sp, "invalid `sym` operand")
-                                .with_span_label(
-                                    self.tcx.def_span(anon_const.def_id),
-                                    format!("is {} `{}`", ty.kind().article(), ty),
-                                )
-                                .with_help(
-                                    "`sym` operands must refer to either a function or a static",
-                                )
-                                .emit();
-                        }
-                    };
+                    debug_assert_matches!(
+                        self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
+                        ty::Error(_) | ty::FnDef(..)
+                    );
                 }
+                // AST lowering guarantees that SymStatic points to a static.
+                hir::InlineAsmOperand::SymStatic { .. } => {}
                 // No special checking is needed for labels.
                 hir::InlineAsmOperand::Label { .. } => {}
             }
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 4c230ad84de..678b8c89a50 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -72,13 +72,11 @@ pub mod intrinsicck;
 mod region;
 pub mod wfcheck;
 
-pub use check::check_abi;
-
 use std::num::NonZero;
 
+pub use check::check_abi;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
-use rustc_errors::ErrorGuaranteed;
-use rustc_errors::{pluralize, struct_span_code_err, Diag};
+use rustc_errors::{pluralize, struct_span_code_err, Diag, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::BitSet;
@@ -87,12 +85,12 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
+use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
+use rustc_span::{BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
@@ -100,11 +98,9 @@ use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 
-use crate::errors;
-use crate::require_c_abi_if_c_variadic;
-
 use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
 use self::region::region_scope_tree;
+use crate::{errors, require_c_abi_if_c_variadic};
 
 pub fn provide(providers: &mut Providers) {
     wfcheck::provide(providers);
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 2b5efd3b2f6..bc6641c688c 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -6,6 +6,8 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
+use std::mem;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -19,8 +21,6 @@ use rustc_span::source_map;
 
 use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut};
 
-use std::mem;
-
 #[derive(Debug, Copy, Clone)]
 pub struct Context {
     /// The scope that contains any new variables declared, plus its depth in
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 456dc4e4e07..a9f8630741a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,14 +1,10 @@
-use crate::autoderef::Autoderef;
-use crate::collect::CollectItemTypesVisitor;
-use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
-use crate::errors;
-use crate::fluent_generated as fluent;
+use std::cell::LazyCell;
+use std::ops::{ControlFlow, Deref};
 
 use hir::intravisit::{self, Visitor};
-use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
-use rustc_hir as hir;
+use rustc_errors::codes::*;
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::lang_items::LangItem;
@@ -20,10 +16,9 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast,
+    self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast,
 };
-use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident};
@@ -41,9 +36,12 @@ use rustc_trait_selection::traits::{
 };
 use rustc_type_ir::solve::NoSolution;
 use rustc_type_ir::TypeFlags;
+use {rustc_ast as ast, rustc_hir as hir};
 
-use std::cell::LazyCell;
-use std::ops::{ControlFlow, Deref};
+use crate::autoderef::Autoderef;
+use crate::collect::CollectItemTypesVisitor;
+use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
+use crate::{errors, fluent_generated as fluent};
 
 pub(super) struct WfCheckingCtxt<'a, 'tcx> {
     pub(super) ocx: ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>,
@@ -1278,7 +1276,7 @@ fn check_item_type(
             UnsizedHandling::Forbid => true,
             UnsizedHandling::Allow => false,
             UnsizedHandling::AllowIfForeignTail => {
-                let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
+                let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.param_env);
                 !matches!(tail.kind(), ty::Foreign(_))
             }
         };
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b35ee270fef..fecd78bc38f 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -1,7 +1,8 @@
 //! Check properties that are required by built-in traits and set
 //! up data structures required by type-checking/codegen.
 
-use crate::errors;
+use std::assert_matches::assert_matches;
+use std::collections::BTreeMap;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
@@ -10,8 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::ItemKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::{self, RegionResolutionError};
+use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -22,9 +22,9 @@ use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
     ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
 };
-use rustc_trait_selection::traits::ObligationCtxt;
-use rustc_trait_selection::traits::{self, ObligationCause};
-use std::collections::BTreeMap;
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
+
+use crate::errors;
 
 pub(super) fn check_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -130,7 +130,7 @@ fn visit_implementation_of_const_param_ty(
     checker: &Checker<'_>,
     kind: LangItem,
 ) -> Result<(), ErrorGuaranteed> {
-    assert!(matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy));
+    assert_matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy);
 
     let tcx = checker.tcx;
     let header = checker.impl_header;
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 3aef29f4ae4..cd5cc33d65a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -1,6 +1,6 @@
-use rustc_data_structures::fx::IndexEntry;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
-use rustc_errors::{codes::*, struct_span_code_err};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, IndexEntry};
+use rustc_errors::codes::*;
+use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index e9961d3ad08..8e4da90ca26 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -5,8 +5,8 @@
 // done by the orphan and overlap modules. Then we build up various
 // mappings. That mapping code resides here.
 
-use crate::errors;
-use rustc_errors::{codes::*, struct_span_code_err};
+use rustc_errors::codes::*;
+use rustc_errors::struct_span_code_err;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::LangItem;
 use rustc_middle::query::Providers;
@@ -14,6 +14,8 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, ErrorGuaranteed};
 
+use crate::errors;
+
 mod builtin;
 mod inherent_impls;
 mod inherent_impls_overlap;
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index f2804ce31fa..dcd0e3111a4 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -1,19 +1,21 @@
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use crate::errors;
-
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
-use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams};
-use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode};
+use rustc_trait_selection::traits::{
+    self, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, UncoveredTyParams,
+};
+
+use crate::errors;
 
 #[instrument(level = "debug", skip(tcx))]
 pub(crate) fn orphan_check_impl(
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index 5fe21e9b822..7513f680271 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -1,10 +1,12 @@
 //! Unsafety checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use rustc_errors::{codes::*, struct_span_code_err};
+use rustc_errors::codes::*;
+use rustc_errors::struct_span_code_err;
 use rustc_hir::Safety;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TraitDef, TyCtxt};
+use rustc_middle::ty::ImplPolarity::*;
+use rustc_middle::ty::{ImplTraitHeader, TraitDef, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::ErrorGuaranteed;
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 565351268c9..91fa066ec6a 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -14,6 +14,10 @@
 //! At present, however, we do run collection across all items in the
 //! crate as a kind of pass. This should eventually be factored away.
 
+use std::cell::Cell;
+use std::iter;
+use std::ops::Bound;
+
 use rustc_ast::Recovered;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
@@ -24,8 +28,7 @@ use rustc_errors::{
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, walk_generics, Visitor};
-use rustc_hir::{self as hir};
-use rustc_hir::{GenericParamKind, Node};
+use rustc_hir::{self as hir, GenericParamKind, Node};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
@@ -39,9 +42,6 @@ use rustc_target::spec::abi;
 use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
-use std::cell::Cell;
-use std::iter;
-use std::ops::Bound;
 
 use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::errors;
@@ -67,6 +67,7 @@ pub fn provide(providers: &mut Providers) {
         item_super_predicates: item_bounds::item_super_predicates,
         explicit_item_super_predicates: item_bounds::explicit_item_super_predicates,
         item_non_self_assumptions: item_bounds::item_non_self_assumptions,
+        impl_super_outlives: item_bounds::impl_super_outlives,
         generics_of: generics_of::generics_of,
         predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
@@ -1207,25 +1208,29 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id);
 
-    let (is_auto, safety, items) = match item.kind {
+    let (is_alias, is_auto, safety, items) = match item.kind {
         hir::ItemKind::Trait(is_auto, safety, .., items) => {
-            (is_auto == hir::IsAuto::Yes, safety, items)
+            (false, is_auto == hir::IsAuto::Yes, safety, items)
         }
-        hir::ItemKind::TraitAlias(..) => (false, hir::Safety::Safe, &[][..]),
+        hir::ItemKind::TraitAlias(..) => (true, false, hir::Safety::Safe, &[][..]),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
-    let constness = if tcx.has_attr(def_id, sym::const_trait) {
+    // Only regular traits can be const.
+    let constness = if !is_alias && tcx.has_attr(def_id, sym::const_trait) {
         hir::Constness::Const
     } else {
         hir::Constness::NotConst
     };
+
     let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
     if paren_sugar && !tcx.features().unboxed_closures {
         tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
     }
 
-    let is_marker = tcx.has_attr(def_id, sym::marker);
+    // Only regular traits can be marker.
+    let is_marker = !is_alias && tcx.has_attr(def_id, sym::marker);
+
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
     let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
 
@@ -1695,6 +1700,8 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
             trait_ref: ty::EarlyBinder::bind(trait_ref),
             safety: impl_.safety,
             polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
+            do_not_recommend: tcx.features().do_not_recommend
+                && tcx.has_attrs_with_path(def_id, &[sym::diagnostic, sym::do_not_recommend]),
         }
     })
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 690423421b9..28d6cab4b43 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -1,10 +1,8 @@
+use std::assert_matches::assert_matches;
 use std::ops::ControlFlow;
 
-use crate::middle::resolve_bound_vars as rbv;
-use hir::{
-    intravisit::{self, Visitor},
-    GenericParamKind, HirId, Node,
-};
+use hir::intravisit::{self, Visitor};
+use hir::{GenericParamKind, HirId, Node};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -13,6 +11,9 @@ use rustc_session::lint;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
+use crate::delegation::inherit_generics_for_delegation_item;
+use crate::middle::resolve_bound_vars as rbv;
+
 #[instrument(level = "debug", skip(tcx), ret)]
 pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     use rustc_hir::*;
@@ -207,9 +208,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 ..
             }) => {
                 if in_trait {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+                    assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
                 } else {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+                    assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
                 }
                 Some(fn_def_id.to_def_id())
             }
@@ -218,15 +219,25 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 ..
             }) => {
                 if in_assoc_ty {
-                    assert!(matches!(tcx.def_kind(parent), DefKind::AssocTy));
+                    assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
                 } else {
-                    assert!(matches!(tcx.def_kind(parent), DefKind::TyAlias));
+                    assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
                 }
                 debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
                 // Opaque types are always nested within another item, and
                 // inherit the generics of the item.
                 Some(parent.to_def_id())
             }
+            ItemKind::Fn(sig, _, _) => {
+                // For a delegation item inherit generics from callee.
+                if let Some(sig_id) = sig.decl.opt_delegation_sig_id()
+                    && let Some(generics) =
+                        inherit_generics_for_delegation_item(tcx, def_id, sig_id)
+                {
+                    return generics;
+                }
+                None
+            }
             _ => None,
         },
         _ => None,
@@ -328,8 +339,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
             if default.is_some() {
                 match allow_defaults {
                     Defaults::Allowed => {}
-                    Defaults::FutureCompatDisallowed
-                        if tcx.features().default_type_parameter_fallback => {}
                     Defaults::FutureCompatDisallowed => {
                         tcx.node_span_lint(
                             lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index c03e074c80b..ec48c781c0e 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -1,15 +1,17 @@
-use super::ItemCtxt;
-use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_infer::traits::util;
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 use rustc_type_ir::Upcast;
 
+use super::ItemCtxt;
+use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
+
 /// For associated types we include both bounds written on the type
 /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
 ///
@@ -210,6 +212,8 @@ pub(super) fn item_super_predicates(
     })
 }
 
+/// This exists as an optimization to compute only the item bounds of the item
+/// that are not `Self` bounds.
 pub(super) fn item_non_self_assumptions(
     tcx: TyCtxt<'_>,
     def_id: DefId,
@@ -224,6 +228,25 @@ pub(super) fn item_non_self_assumptions(
     }
 }
 
+/// This exists as an optimization to compute only the supertraits of this impl's
+/// trait that are outlives bounds.
+pub(super) fn impl_super_outlives(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
+    tcx.impl_trait_header(def_id).expect("expected an impl of trait").trait_ref.map_bound(
+        |trait_ref| {
+            let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
+            tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
+                matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
+                )
+            }))
+        },
+    )
+}
+
 struct AssocTyToOpaque<'tcx> {
     tcx: TyCtxt<'tcx>,
     fn_def_id: DefId,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 9e430c83e20..6ac4802b195 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,19 +1,22 @@
-use crate::bounds::Bounds;
-use crate::collect::ItemCtxt;
-use crate::constrained_generic_params as cgp;
-use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
+use std::assert_matches::assert_matches;
+
 use hir::{HirId, Node};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, Upcast};
+use rustc_middle::ty::{self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
+use crate::bounds::Bounds;
+use crate::collect::ItemCtxt;
+use crate::constrained_generic_params as cgp;
+use crate::delegation::inherit_predicates_for_delegation_item;
+use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
+
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
 /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
 /// `Self: Trait` predicates for traits.
@@ -143,6 +146,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => {
                 is_trait = Some(self_bounds);
             }
+
+            ItemKind::Fn(sig, _, _) => {
+                // For a delegation item inherit predicates from callee.
+                if let Some(sig_id) = sig.decl.opt_delegation_sig_id()
+                    && let Some(predicates) =
+                        inherit_predicates_for_delegation_item(tcx, def_id, sig_id)
+                {
+                    return predicates;
+                }
+            }
             _ => {}
         }
     };
@@ -590,7 +603,7 @@ pub(super) fn implied_predicates_with_filter(
     let Some(trait_def_id) = trait_def_id.as_local() else {
         // if `assoc_name` is None, then the query should've been redirected to an
         // external provider
-        assert!(matches!(filter, PredicateFilter::SelfThatDefines(_)));
+        assert_matches!(filter, PredicateFilter::SelfThatDefines(_));
         return tcx.explicit_super_predicates_of(trait_def_id);
     };
 
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 02ea95852f0..e11d3c9c48b 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -7,6 +7,8 @@
 //! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
 
 use core::ops::ControlFlow;
+use std::fmt;
+
 use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir as hir;
@@ -23,7 +25,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
-use std::fmt;
 
 use crate::errors;
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 9affd654366..8cb4ba6c669 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -1,4 +1,5 @@
 use core::ops::ControlFlow;
+
 use rustc_errors::{Applicability, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -6,17 +7,15 @@ use rustc_hir::HirId;
 use rustc_middle::query::plumbing::CyclePlaceholder;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
+use super::{bad_placeholder, ItemCtxt};
 use crate::errors::TypeofReservedKeywordUsed;
 use crate::hir_ty_lowering::HirTyLowerer;
 
-use super::bad_placeholder;
-use super::ItemCtxt;
-
 mod opaque;
 
 fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
@@ -35,6 +34,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
     let parent_node_id = tcx.parent_hir_id(hir_id);
     let parent_node = tcx.hir_node(parent_node_id);
 
+    let find_sym_fn = |&(op, op_sp)| match op {
+        hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => {
+            Some((anon_const, op_sp))
+        }
+        _ => None,
+    };
+
+    let find_const = |&(op, op_sp)| match op {
+        hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
+            Some((anon_const, op_sp))
+        }
+        _ => None,
+    };
+
     match parent_node {
         // Anon consts "inside" the type system.
         Node::ConstArg(&ConstArg {
@@ -46,13 +59,51 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
         // Anon consts outside the type system.
         Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
         | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
-            if asm.operands.iter().any(|(op, _op_sp)| match op {
-                hir::InlineAsmOperand::Const { anon_const }
-                | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
-                _ => false,
-            }) =>
+            if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) =>
         {
-            tcx.typeck(def_id).node_type(hir_id)
+            let ty = tcx.typeck(def_id).node_type(hir_id);
+
+            match ty.kind() {
+                ty::Error(_) => ty,
+                ty::FnDef(..) => ty,
+                _ => {
+                    let guar = tcx
+                        .dcx()
+                        .struct_span_err(op_sp, "invalid `sym` operand")
+                        .with_span_label(
+                            tcx.def_span(anon_const.def_id),
+                            format!("is {} `{}`", ty.kind().article(), ty),
+                        )
+                        .with_help("`sym` operands must refer to either a function or a static")
+                        .emit();
+
+                    Ty::new_error(tcx, guar)
+                }
+            }
+        }
+        Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+        | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
+            if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
+        {
+            let ty = tcx.typeck(def_id).node_type(hir_id);
+
+            match ty.kind() {
+                ty::Error(_) => ty,
+                ty::Int(_) | ty::Uint(_) => ty,
+                _ => {
+                    let guar = tcx
+                        .dcx()
+                        .struct_span_err(op_sp, "invalid type for `const` operand")
+                        .with_span_label(
+                            tcx.def_span(anon_const.def_id),
+                            format!("is {} `{}`", ty.kind().article(), ty),
+                        )
+                        .with_help("`const` operands must be of an integer type")
+                        .emit();
+
+                    Ty::new_error(tcx, guar)
+                }
+            }
         }
         Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
             tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
new file mode 100644
index 00000000000..20aaa43219f
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -0,0 +1,261 @@
+use std::assert_matches::debug_assert_matches;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::ErrorGuaranteed;
+use rustc_type_ir::visit::TypeVisitableExt;
+
+type RemapTable = FxHashMap<u32, u32>;
+
+struct ParamIndexRemapper<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    remap_table: RemapTable,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamIndexRemapper<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if !ty.has_param() {
+            return ty;
+        }
+
+        if let ty::Param(param) = ty.kind()
+            && let Some(index) = self.remap_table.get(&param.index)
+        {
+            return Ty::new_param(self.tcx, *index, param.name);
+        }
+        ty.super_fold_with(self)
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReEarlyParam(param) = r.kind()
+            && let Some(index) = self.remap_table.get(&param.index).copied()
+        {
+            return ty::Region::new_early_param(
+                self.tcx,
+                ty::EarlyParamRegion { index, name: param.name },
+            );
+        }
+        r
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Param(param) = ct.kind()
+            && let Some(idx) = self.remap_table.get(&param.index)
+        {
+            let param = ty::ParamConst::new(*idx, param.name);
+            return ty::Const::new_param(self.tcx, param);
+        }
+        ct.super_fold_with(self)
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum FnKind {
+    Free,
+    AssocInherentImpl,
+    AssocTrait,
+    AssocTraitImpl,
+}
+
+fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind {
+    debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
+
+    let parent = tcx.parent(def_id);
+    match tcx.def_kind(parent) {
+        DefKind::Trait => FnKind::AssocTrait,
+        DefKind::Impl { of_trait: true } => FnKind::AssocTraitImpl,
+        DefKind::Impl { of_trait: false } => FnKind::AssocInherentImpl,
+        _ => FnKind::Free,
+    }
+}
+
+fn create_generic_args<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    sig_id: DefId,
+) -> ty::GenericArgsRef<'tcx> {
+    let caller_generics = tcx.generics_of(def_id);
+    let callee_generics = tcx.generics_of(sig_id);
+
+    let caller_kind = fn_kind(tcx, def_id.into());
+    let callee_kind = fn_kind(tcx, sig_id);
+    // FIXME(fn_delegation): Support generics on associated delegation items.
+    // Error will be reported in `check_constraints`.
+    match (caller_kind, callee_kind) {
+        (FnKind::Free, _) => {
+            // Lifetime parameters must be declared before type and const parameters.
+            // Therefore, When delegating from a free function to a associated function,
+            // generic parameters need to be reordered:
+            //
+            // trait Trait<'a, A> {
+            //     fn foo<'b, B>(...) {...}
+            // }
+            //
+            // reuse Trait::foo;
+            // desugaring:
+            // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
+            //     Trait::foo(...)
+            // }
+            let mut remap_table = RemapTable::default();
+            for caller_param in &caller_generics.own_params {
+                let callee_index =
+                    callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap();
+                remap_table.insert(callee_index, caller_param.index);
+            }
+            let mut folder = ParamIndexRemapper { tcx, remap_table };
+            ty::GenericArgs::identity_for_item(tcx, sig_id).fold_with(&mut folder)
+        }
+        // FIXME(fn_delegation): Only `Self` param supported here.
+        (FnKind::AssocTraitImpl, FnKind::AssocTrait)
+        | (FnKind::AssocInherentImpl, FnKind::AssocTrait) => {
+            let parent = tcx.parent(def_id.into());
+            let self_ty = tcx.type_of(parent).instantiate_identity();
+            let generic_self_ty = ty::GenericArg::from(self_ty);
+            tcx.mk_args_from_iter(std::iter::once(generic_self_ty))
+        }
+        _ => ty::GenericArgs::identity_for_item(tcx, sig_id),
+    }
+}
+
+pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    sig_id: DefId,
+) -> Option<ty::Generics> {
+    // FIXME(fn_delegation): Support generics on associated delegation items.
+    // Error will be reported in `check_constraints`.
+    if fn_kind(tcx, def_id.into()) != FnKind::Free {
+        return None;
+    }
+
+    let mut own_params = vec![];
+
+    let callee_generics = tcx.generics_of(sig_id);
+    if let Some(parent_sig_id) = callee_generics.parent {
+        let parent_sig_generics = tcx.generics_of(parent_sig_id);
+        own_params.append(&mut parent_sig_generics.own_params.clone());
+    }
+    own_params.append(&mut callee_generics.own_params.clone());
+
+    // Lifetimes go first.
+    own_params.sort_by_key(|key| key.kind.is_ty_or_const());
+
+    for (idx, param) in own_params.iter_mut().enumerate() {
+        param.index = idx as u32;
+        // Default parameters are not inherited: they are not allowed
+        // in fn's.
+        if let ty::GenericParamDefKind::Type { has_default, .. }
+        | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
+        {
+            *has_default = false;
+        }
+    }
+
+    let param_def_id_to_index =
+        own_params.iter().map(|param| (param.def_id, param.index)).collect();
+
+    Some(ty::Generics {
+        parent: None,
+        parent_count: 0,
+        own_params,
+        param_def_id_to_index,
+        has_self: false,
+        has_late_bound_regions: callee_generics.has_late_bound_regions,
+        host_effect_index: callee_generics.host_effect_index,
+    })
+}
+
+pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    sig_id: DefId,
+) -> Option<ty::GenericPredicates<'tcx>> {
+    // FIXME(fn_delegation): Support generics on associated delegation items.
+    // Error will be reported in `check_constraints`.
+    if fn_kind(tcx, def_id.into()) != FnKind::Free {
+        return None;
+    }
+
+    let callee_predicates = tcx.predicates_of(sig_id);
+    let args = create_generic_args(tcx, def_id, sig_id);
+
+    let mut preds = vec![];
+    if let Some(parent_id) = callee_predicates.parent {
+        preds.extend(tcx.predicates_of(parent_id).instantiate_own(tcx, args));
+    }
+    preds.extend(callee_predicates.instantiate_own(tcx, args));
+
+    Some(ty::GenericPredicates {
+        parent: None,
+        predicates: tcx.arena.alloc_from_iter(preds),
+        effects_min_tys: ty::List::empty(),
+    })
+}
+
+fn check_constraints<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    sig_id: DefId,
+) -> Result<(), ErrorGuaranteed> {
+    let mut ret = Ok(());
+
+    let mut emit = |descr| {
+        ret = Err(tcx.dcx().emit_err(crate::errors::UnsupportedDelegation {
+            span: tcx.def_span(def_id),
+            descr,
+            callee_span: tcx.def_span(sig_id),
+        }));
+    };
+
+    if tcx.has_host_param(sig_id) {
+        emit("delegation to a function with effect parameter is not supported yet");
+    }
+
+    if let Some(local_sig_id) = sig_id.as_local()
+        && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some()
+    {
+        emit("recursive delegation is not supported yet");
+    }
+
+    if fn_kind(tcx, def_id.into()) != FnKind::Free {
+        let sig_generics = tcx.generics_of(sig_id);
+        let parent = tcx.parent(def_id.into());
+        let parent_generics = tcx.generics_of(parent);
+
+        let parent_has_self = parent_generics.has_self as usize;
+        let sig_has_self = sig_generics.has_self as usize;
+
+        if sig_generics.count() > sig_has_self || parent_generics.count() > parent_has_self {
+            emit("early bound generics are not supported for associated delegation items");
+        }
+    }
+
+    ret
+}
+
+pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> &'tcx [Ty<'tcx>] {
+    let sig_id = tcx.hir().opt_delegation_sig_id(def_id).unwrap();
+    let caller_sig = tcx.fn_sig(sig_id);
+    if let Err(err) = check_constraints(tcx, def_id, sig_id) {
+        let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1;
+        let err_type = Ty::new_error(tcx, err);
+        return tcx.arena.alloc_from_iter((0..sig_len).map(|_| err_type));
+    }
+    let args = create_generic_args(tcx, def_id, sig_id);
+
+    // Bound vars are also inherited from `sig_id`.
+    // They will be rebound later in `lower_fn_ty`.
+    let sig = caller_sig.instantiate(tcx, args).skip_binder();
+    let sig_iter = sig.inputs().iter().cloned().chain(std::iter::once(sig.output()));
+    tcx.arena.alloc_from_iter(sig_iter)
+}
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c364a561631..7034735aec0 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,12 +1,15 @@
 //! Errors emitted by `rustc_hir_analysis`.
 
-use crate::fluent_generated as fluent;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan,
+    Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
-use rustc_span::{symbol::Ident, Span, Symbol};
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
+
+use crate::fluent_generated as fluent;
 mod pattern_types;
 pub use pattern_types::*;
 pub mod wrong_number_of_generic_args;
@@ -1572,7 +1575,7 @@ pub struct RefOfMutStatic<'a> {
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_not_supported_delegation)]
-pub struct NotSupportedDelegation<'a> {
+pub struct UnsupportedDelegation<'a> {
     #[primary_span]
     pub span: Span,
     pub descr: &'a str,
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index db91a6ab2f4..8ecf53bfacb 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -1,11 +1,10 @@
-use rustc_errors::{
-    codes::*, pluralize, Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan,
-};
+use std::iter;
+
+use rustc_errors::codes::*;
+use rustc_errors::{pluralize, Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan};
 use rustc_hir as hir;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_span::def_id::DefId;
-use std::iter;
-
 use GenericArgsInfo::*;
 
 /// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 30c04aa47a3..7f4c75d3a6a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -1,7 +1,8 @@
 use std::ops::ControlFlow;
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_errors::{codes::*, struct_span_code_err};
+use rustc_errors::codes::*;
+use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,8 +16,9 @@ use smallvec::SmallVec;
 
 use crate::bounds::Bounds;
 use crate::errors;
-use crate::hir_ty_lowering::HirTyLowerer;
-use crate::hir_ty_lowering::{AssocItemQSelf, OnlySelfBounds, PredicateFilter, RegionInferReason};
+use crate::hir_ty_lowering::{
+    AssocItemQSelf, HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Add a `Sized` bound to the `bounds` if appropriate.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 20f06d77489..d77cbe30536 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1,15 +1,9 @@
-use crate::errors::{
-    self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
-    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
-};
-use crate::fluent_generated as fluent;
-use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
-use rustc_errors::MultiSpan;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
+    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -17,21 +11,26 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::query::Key;
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
-use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, suggest_constraining_type_param};
-use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{Binder, TraitRef};
+use rustc_middle::ty::{
+    self, suggest_constraining_type_param, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty,
+    TyCtxt, TypeVisitableExt,
+};
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::BytePos;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{BytePos, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
-use rustc_trait_selection::traits::FulfillmentError;
 use rustc_trait_selection::traits::{
-    object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
+    object_safety_violations_for_assoc_item, FulfillmentError, TraitAliasExpansionInfo,
 };
 
+use crate::errors::{
+    self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
+    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
+};
+use crate::fluent_generated as fluent;
+use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
+
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index abe2cff321f..a59e9aa85fd 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -1,13 +1,6 @@
-use super::{HirTyLowerer, IsMethodCall};
-use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs};
-use crate::hir_ty_lowering::{
-    errors::prohibit_assoc_item_constraint, ExplicitLateBound, GenericArgCountMismatch,
-    GenericArgCountResult, GenericArgPosition, GenericArgsLowerer,
-};
 use rustc_ast::ast::ParamKindOrd;
-use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
-};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -19,6 +12,14 @@ use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::symbol::{kw, sym};
 use smallvec::SmallVec;
 
+use super::{HirTyLowerer, IsMethodCall};
+use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs};
+use crate::hir_ty_lowering::errors::prohibit_assoc_item_constraint;
+use crate::hir_ty_lowering::{
+    ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
+    GenericArgsLowerer,
+};
+
 /// Report an error that a generic argument did not match the generic parameter that was
 /// expected.
 fn generic_arg_mismatch_err(
@@ -252,32 +253,6 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
             match (args_iter.peek(), params.peek()) {
                 (Some(&arg), Some(&param)) => {
                     match (arg, &param.kind, arg_count.explicit_late_bound) {
-                        (
-                            GenericArg::Const(hir::ConstArg {
-                                is_desugared_from_effects: true,
-                                ..
-                            }),
-                            GenericParamDefKind::Const { is_host_effect: false, .. }
-                            | GenericParamDefKind::Type { .. }
-                            | GenericParamDefKind::Lifetime,
-                            _,
-                        ) => {
-                            // FIXME(effects): this should be removed
-                            // SPECIAL CASE FOR DESUGARED EFFECT PARAMS
-                            // This comes from the following example:
-                            //
-                            // ```
-                            // #[const_trait]
-                            // pub trait PartialEq<Rhs: ?Sized = Self> {}
-                            // impl const PartialEq for () {}
-                            // ```
-                            //
-                            // Since this is a const impl, we need to insert a host arg at the end of
-                            // `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
-                            // To work around this, we infer all arguments until we reach the host param.
-                            args.push(ctx.inferred_kind(&args, param, infer_args));
-                            params.next();
-                        }
                         (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
                         | (
                             GenericArg::Type(_) | GenericArg::Infer(_),
@@ -551,21 +526,34 @@ pub(crate) fn check_generic_arg_count(
                 synth_provided,
             }
         } else {
-            let num_missing_args = expected_max - provided;
+            // Check if associated type bounds are incorrectly written in impl block header like:
+            // ```
+            // trait Foo<T> {}
+            // impl Foo<T: Default> for u8 {}
+            // ```
+            let parent_is_impl_block = cx
+                .tcx()
+                .hir()
+                .parent_owner_iter(seg.hir_id)
+                .next()
+                .is_some_and(|(_, owner_node)| owner_node.is_impl_block());
+            if parent_is_impl_block {
+                let constraint_names: Vec<_> =
+                    gen_args.constraints.iter().map(|b| b.ident.name).collect();
+                let param_names: Vec<_> = gen_params
+                    .own_params
+                    .iter()
+                    .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter
+                    .map(|param| param.name)
+                    .collect();
+                if constraint_names == param_names {
+                    // We set this to true and delay emitting `WrongNumberOfGenericArgs`
+                    // to provide a succinct error for cases like issue #113073
+                    all_params_are_binded = true;
+                };
+            }
 
-            let constraint_names: Vec<_> =
-                gen_args.constraints.iter().map(|b| b.ident.name).collect();
-            let param_names: Vec<_> = gen_params
-                .own_params
-                .iter()
-                .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter
-                .map(|param| param.name)
-                .collect();
-            if constraint_names == param_names {
-                // We set this to true and delay emitting `WrongNumberOfGenericArgs`
-                // to provide a succinct error for cases like issue #113073
-                all_params_are_binded = true;
-            };
+            let num_missing_args = expected_max - provided;
 
             GenericArgsInfo::MissingTypesOrConsts {
                 num_missing_args,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index e7aad0a29c5..6aff518390f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -1,8 +1,10 @@
 use rustc_ast::TraitObjectSyntax;
-use rustc_errors::{codes::*, Diag, EmissionGuarantee, StashKey};
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, EmissionGuarantee, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
+use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS;
+use rustc_lint_defs::Applicability;
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index ce298641e60..d865357b829 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -20,17 +20,13 @@ pub mod generics;
 mod lint;
 mod object_safety;
 
-use crate::bounds::Bounds;
-use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
-use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
-use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
-use crate::middle::resolve_bound_vars as rbv;
-use crate::require_c_abi_if_c_variadic;
+use std::slice;
+
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed,
-    FatalError,
+    struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -55,7 +51,12 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
-use std::slice;
+use crate::bounds::Bounds;
+use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
+use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
+use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
+use crate::middle::resolve_bound_vars as rbv;
+use crate::require_c_abi_if_c_variadic;
 
 /// A path segment that is semantically allowed to have generic arguments.
 #[derive(Debug)]
@@ -2006,93 +2007,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self.lower_ty_common(hir_ty, false, true)
     }
 
-    fn check_delegation_constraints(&self, sig_id: DefId, span: Span, emit: bool) -> bool {
-        let mut error_occured = false;
-        let sig_span = self.tcx().def_span(sig_id);
-        let mut try_emit = |descr| {
-            if emit {
-                self.dcx().emit_err(crate::errors::NotSupportedDelegation {
-                    span,
-                    descr,
-                    callee_span: sig_span,
-                });
-            }
-            error_occured = true;
-        };
-
-        if let Some(node) = self.tcx().hir().get_if_local(sig_id)
-            && let Some(decl) = node.fn_decl()
-            && let hir::FnRetTy::Return(ty) = decl.output
-            && let hir::TyKind::InferDelegation(_, _) = ty.kind
-        {
-            try_emit("recursive delegation");
-        }
-
-        let sig_generics = self.tcx().generics_of(sig_id);
-        let parent = self.tcx().local_parent(self.item_def_id());
-        let parent_generics = self.tcx().generics_of(parent);
-
-        let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
-        let sig_has_self = sig_generics.has_self as usize;
-
-        if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait {
-            try_emit("delegation with early bound generics");
-        }
-
-        // There is no way to instantiate `Self` param for caller if
-        // 1. callee is a trait method
-        // 2. delegation item isn't an associative item
-        if let DefKind::AssocFn = self.tcx().def_kind(sig_id)
-            && let DefKind::Fn = self.tcx().def_kind(self.item_def_id())
-            && self.tcx().associated_item(sig_id).container
-                == ty::AssocItemContainer::TraitContainer
-        {
-            try_emit("delegation to a trait method from a free function");
-        }
-
-        error_occured
-    }
-
-    fn lower_delegation_ty(
-        &self,
-        sig_id: DefId,
-        idx: hir::InferDelegationKind,
-        span: Span,
-    ) -> Ty<'tcx> {
-        if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
-        {
-            let e = self.dcx().span_delayed_bug(span, "not supported delegation case");
-            return Ty::new_error(self.tcx(), e);
-        };
-        let sig = self.tcx().fn_sig(sig_id);
-        let sig_generics = self.tcx().generics_of(sig_id);
-
-        let parent = self.tcx().local_parent(self.item_def_id());
-        let parent_def_kind = self.tcx().def_kind(parent);
-
-        let sig = if let DefKind::Impl { .. } = parent_def_kind
-            && sig_generics.has_self
-        {
-            // Generic params can't be here except the trait self type.
-            // They are not supported yet.
-            assert_eq!(sig_generics.count(), 1);
-            assert_eq!(self.tcx().generics_of(parent).count(), 0);
-
-            let self_ty = self.tcx().type_of(parent).instantiate_identity();
-            let generic_self_ty = ty::GenericArg::from(self_ty);
-            let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
-            sig.instantiate(self.tcx(), args)
-        } else {
-            sig.instantiate_identity()
-        };
-
-        // Bound vars are also inherited from `sig_id`.
-        // They will be rebound later in `lower_fn_ty`.
-        let sig = sig.skip_binder();
-
+    fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
+        let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
         match idx {
-            hir::InferDelegationKind::Input(id) => sig.inputs()[id],
-            hir::InferDelegationKind::Output => sig.output(),
+            hir::InferDelegationKind::Input(idx) => delegation_sig[idx],
+            hir::InferDelegationKind::Output => *delegation_sig.last().unwrap(),
         }
     }
 
@@ -2109,9 +2028,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
 
         let result_ty = match &hir_ty.kind {
-            hir::TyKind::InferDelegation(sig_id, idx) => {
-                self.lower_delegation_ty(*sig_id, *idx, hir_ty.span)
-            }
+            hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx),
             hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
             hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
             hir::TyKind::Ref(region, mt) => {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index b3c7a1ff8a8..31d1750f33d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -1,24 +1,25 @@
-use crate::bounds::Bounds;
-use crate::hir_ty_lowering::{
-    GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
-};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_errors::{codes::*, struct_span_code_err};
+use rustc_errors::codes::*;
+use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{DynKind, Upcast};
+use rustc_middle::ty::{
+    self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
+};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
-
 use smallvec::{smallvec, SmallVec};
 
 use super::HirTyLowerer;
+use crate::bounds::Bounds;
+use crate::hir_ty_lowering::{
+    GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Lower a trait object type from the HIR to our internal notion of a type.
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 13993a1992b..7d2cabd3f2c 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -1,4 +1,3 @@
-use crate::collect::ItemCtxt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{ForeignItem, ForeignItemKind};
@@ -10,6 +9,8 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
+use crate::collect::ItemCtxt;
+
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { diagnostic_hir_wf_check, ..*providers };
 }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index f0fcbd5528f..ab441ed4cde 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -8,9 +8,9 @@
 //! specialization errors. These things can (and probably should) be
 //! fixed, but for the moment it's easier to do these checks early.
 
-use crate::{constrained_generic_params as cgp, errors::UnconstrainedGenericParameter};
-use min_specialization::check_min_specialization;
+use std::assert_matches::debug_assert_matches;
 
+use min_specialization::check_min_specialization;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::codes::*;
 use rustc_hir::def::DefKind;
@@ -18,6 +18,9 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_span::ErrorGuaranteed;
 
+use crate::constrained_generic_params as cgp;
+use crate::errors::UnconstrainedGenericParameter;
+
 mod min_specialization;
 
 /// Checks that all the type/lifetime parameters on an impl also
@@ -53,7 +56,7 @@ mod min_specialization;
 pub fn check_impl_wf(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
     let min_specialization = tcx.features().min_specialization;
     let mut res = Ok(());
-    debug_assert!(matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. }));
+    debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
     res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id));
     if min_specialization {
         res = res.and(check_min_specialization(tcx, impl_def_id));
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 2e5f99bb78b..f44a78bac4d 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -65,9 +65,6 @@
 //! cause use after frees with purely safe code in the same way as specializing
 //! on traits with methods can.
 
-use crate::errors::GenericArgsOnOverriddenImpl;
-use crate::{constrained_generic_params as cgp, errors};
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -75,13 +72,15 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
-use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef};
+use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt};
 
+use crate::errors::GenericArgsOnOverriddenImpl;
+use crate::{constrained_generic_params as cgp, errors};
+
 pub(super) fn check_min_specialization(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 89b981ab80d..291d57f2a17 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -62,6 +62,7 @@ This API is completely unstable and subject to change.
 #![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
@@ -83,6 +84,7 @@ pub mod autoderef;
 mod bounds;
 mod check_unused;
 mod coherence;
+mod delegation;
 pub mod hir_ty_lowering;
 // FIXME: This module shouldn't be public.
 pub mod collect;
@@ -100,7 +102,8 @@ use rustc_middle::mir::interpret::GlobalId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::parse::feature_err;
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 
@@ -145,6 +148,10 @@ pub fn provide(providers: &mut Providers) {
     variance::provide(providers);
     outlives::provide(providers);
     hir_wf_check::provide(providers);
+    *providers = Providers {
+        inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
+        ..*providers
+    };
 }
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index d953736c28c..454c20d3e64 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -1,8 +1,7 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt};
 use rustc_span::Span;
 
 use super::explicit::ExplicitPredicatesMap;
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index 1f74ebf99f1..cb61ef7c64d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -1,8 +1,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast};
+use rustc_middle::ty::{self, CratePredicatesMap, GenericArgKind, TyCtxt, Upcast};
 use rustc_span::Span;
 
 pub(crate) mod dump;
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 08015c28a26..a1eccc91dea 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -1,6 +1,5 @@
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, GenericArg, GenericArgKind, Region, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_type_ir::outlives::{push_outlives_components, Component};
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 0c436e21c16..92baa41e07f 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -6,8 +6,7 @@
 use hir::def_id::{DefId, LocalDefId};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 
 use super::terms::VarianceTerm::*;
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 29f96e27b64..8a4114c3e4b 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -9,8 +9,9 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{
+    self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+};
 
 /// Defines the `TermsContext` basically houses an arena where we can
 /// allocate terms.
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 275df24956c..36bff60e019 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -9,11 +9,12 @@
 // `InferredIndex` is a newtype'd int representing the index of such
 // a variable.
 
+use std::fmt;
+
 use rustc_arena::DroplessArena;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
 use rustc_middle::ty::{self, TyCtxt};
-use std::fmt;
 
 use self::VarianceTerm::*;
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index e25f43e169d..089cee2fa0d 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -5,12 +5,13 @@
 #![recursion_limit = "256"]
 // tidy-alphabetical-end
 
-use rustc_ast as ast;
+use std::cell::Cell;
+use std::vec;
+
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
 use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::{Comments, PrintState};
-use rustc_hir as hir;
 use rustc_hir::{
     BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
     HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
@@ -20,9 +21,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::FileName;
 use rustc_target::spec::abi::Abi;
-
-use std::cell::Cell;
-use std::vec;
+use {rustc_ast as ast, rustc_hir as hir};
 
 pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: HirId) -> String {
     to_string(&map, |s| s.print_node(map.hir_node(hir_id)))
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 4e2104ff561..bc0ed4a7fa9 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,5 +1,3 @@
-use crate::coercion::{AsCoercionSite, CoerceMany};
-use crate::{Diverges, Expectation, FnCtxt, Needs};
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
@@ -11,6 +9,9 @@ use rustc_trait_selection::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
 };
 
+use crate::coercion::{AsCoercionSite, CoerceMany};
+use crate::{Diverges, Expectation, FnCtxt, Needs};
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug", ret)]
     pub fn check_match(
diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 5db71591e66..69c4889d7a4 100644
--- a/compiler/rustc_hir_typeck/src/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
@@ -1,7 +1,6 @@
 //! Some helper functions for `AutoDeref`.
 
-use super::method::MethodCallee;
-use super::{FnCtxt, PlaceOp};
+use std::iter;
 
 use itertools::Itertools;
 use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind};
@@ -10,7 +9,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 
-use std::iter;
+use super::method::MethodCallee;
+use super::{FnCtxt, PlaceOp};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 0d2a55a9507..07f64ead6f6 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,24 +1,17 @@
-use super::method::probe::ProbeScope;
-use super::method::MethodCallee;
-use super::{Expectation, FnCtxt, TupleArgumentsFlag};
+use std::{iter, slice};
 
-use crate::errors;
 use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
 use rustc_hir::def::{self, CtorKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
 use rustc_hir_analysis::autoderef::Autoderef;
-use rustc_infer::traits::ObligationCauseCode;
-use rustc_infer::{
-    infer,
-    traits::{self, Obligation, ObligationCause},
-};
+use rustc_infer::infer;
+use rustc_infer::traits::{self, Obligation, ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident};
@@ -28,7 +21,10 @@ use rustc_trait_selection::error_reporting::traits::DefIdOrName;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
-use std::{iter, slice};
+use super::method::probe::ProbeScope;
+use super::method::MethodCallee;
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
+use crate::errors;
 
 /// Checks that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 65229722771..7cd97166ed1 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -28,12 +28,9 @@
 //! expression, `e as U2` is not necessarily so (in fact it will only be valid if
 //! `U1` coerces to `U2`).
 
-use super::FnCtxt;
-
-use crate::errors;
-use crate::type_error_struct;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
+use rustc_errors::codes::*;
+use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_hir::{self as hir, ExprKind};
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
@@ -41,15 +38,16 @@ use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef};
 use rustc_session::lint;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::sym;
-use rustc_span::Span;
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
 
+use super::FnCtxt;
+use crate::{errors, type_error_struct};
+
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
 #[derive(Debug)]
@@ -99,6 +97,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return Ok(Some(PointerKind::Thin));
         }
 
+        let t = self.try_structurally_resolve_type(span, t);
+
         Ok(match *t.kind() {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
             ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 843d9e38714..89df464cca0 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -1,8 +1,5 @@
 use std::cell::RefCell;
 
-use crate::coercion::CoerceMany;
-use crate::gather_locals::GatherLocalsVisitor;
-use crate::{CoroutineTypes, Diverges, FnCtxt};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::Visitor;
@@ -16,6 +13,10 @@ use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 
+use crate::coercion::CoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use crate::{CoroutineTypes, Diverges, FnCtxt};
+
 /// Helper used for fns and closures. Does the grungy work of checking a function
 /// body and returns the function context used for that purpose, since in the case of a fn item
 /// there is still a bit more to do.
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 79854976bdd..a7953acc95c 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -1,27 +1,26 @@
 //! Code for type-checking closure expressions.
 
-use super::{check_fn, CoroutineTypes, Expectation, FnCtxt};
+use std::iter;
+use std::ops::ControlFlow;
 
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
-use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
-use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::span_bug;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::traits::ArgKind;
 use rustc_trait_selection::traits;
 use rustc_type_ir::ClosureKind;
-use std::iter;
-use std::ops::ControlFlow;
+
+use super::{check_fn, CoroutineTypes, Expectation, FnCtxt};
 
 /// What signature do we *expect* the closure to have from context?
 #[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 1bfe9734217..fcd3798eb48 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -35,16 +35,18 @@
 //! // and are then unable to coerce `&7i32` to `&mut i32`.
 //! ```
 
-use crate::errors::SuggestBoxingForReturnImplTrait;
-use crate::FnCtxt;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag};
+use std::ops::Deref;
+
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer::relate::RelateResult;
 use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
-use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause};
-use rustc_infer::traits::{Obligation, PredicateObligation};
+use rustc_infer::traits::{
+    IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
+};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::span_bug;
 use rustc_middle::traits::BuiltinImplSource;
@@ -63,9 +65,10 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
     self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
 };
-
 use smallvec::{smallvec, SmallVec};
-use std::ops::Deref;
+
+use crate::errors::SuggestBoxingForReturnImplTrait;
+use crate::FnCtxt;
 
 struct Coerce<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 4f1c2fdd922..0a9fa5c64a5 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,6 +1,4 @@
-use crate::FnCtxt;
-use rustc_errors::MultiSpan;
-use rustc_errors::{Applicability, Diag};
+use rustc_errors::{Applicability, Diag, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::Visitor;
@@ -17,6 +15,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCause;
 
 use super::method::probe;
+use crate::FnCtxt;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn emit_type_mismatch_suggestions(
diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs
index 0b559a0858e..aa30fb0f0af 100644
--- a/compiler/rustc_hir_typeck/src/diverges.rs
+++ b/compiler/rustc_hir_typeck/src/diverges.rs
@@ -1,6 +1,7 @@
-use rustc_span::{Span, DUMMY_SP};
 use std::{cmp, ops};
 
+use rustc_span::{Span, DUMMY_SP};
+
 /// Tracks whether executing a node may exit normally (versus
 /// return/break/panic, which "diverge", leaving dead code in their
 /// wake). Tracked semi-automatically (through type variables marked
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 9a38d6d4a71..f802b8cf9cc 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -2,18 +2,18 @@
 
 use std::borrow::Cow;
 
-use crate::fluent_generated as fluent;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg,
-    MultiSpan, SubdiagMessageOp, Subdiagnostic,
+    Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan,
+    SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
-use rustc_span::{
-    edition::{Edition, LATEST_STABLE_EDITION},
-    symbol::Ident,
-    Span, Symbol,
-};
+use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
+
+use crate::fluent_generated as fluent;
 
 #[derive(Diagnostic)]
 #[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)]
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index 91deae4174b..76ae41db5c5 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -70,7 +70,8 @@ impl<'a, 'tcx> Expectation<'tcx> {
     /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
     /// for examples of where this comes up,.
     pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
-        match fcx.tcx.struct_tail_without_normalization(ty).kind() {
+        // FIXME: This is not right, even in the old solver...
+        match fcx.tcx.struct_tail_raw(ty, |ty| ty, || {}).kind() {
             ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
             _ => ExpectHasType(ty),
         }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 0d002c52fbb..fec6efdc0f7 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2,33 +2,13 @@
 //!
 //! See [`rustc_hir_analysis::check`] for more context on type checking in general.
 
-use crate::cast;
-use crate::coercion::CoerceMany;
-use crate::coercion::DynamicCoerceMany;
-use crate::errors::ReturnLikeStatementKind;
-use crate::errors::TypeMismatchFruTypo;
-use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
-use crate::errors::{
-    FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition,
-    YieldExprOutsideOfCoroutine,
-};
-use crate::fatally_break_rust;
-use crate::type_error_struct;
-use crate::CoroutineTypes;
-use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
-use crate::{
-    report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
-    TupleArgumentsFlag::DontTupleArguments,
-};
-use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::UnordMap;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey,
-    Subdiagnostic,
+    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
@@ -36,14 +16,12 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, HirId, QPath};
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
 use rustc_infer::infer;
-use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_infer::infer::InferOk;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_session::parse::feature_err;
@@ -54,10 +32,23 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::ObligationCtxt;
-use rustc_trait_selection::traits::{self, ObligationCauseCode};
-
+use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
 use smallvec::SmallVec;
+use {rustc_ast as ast, rustc_hir as hir};
+
+use crate::coercion::{CoerceMany, DynamicCoerceMany};
+use crate::errors::{
+    AddressOfTemporaryTaken, FieldMultiplySpecifiedInInitializer,
+    FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, ReturnLikeStatementKind,
+    ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo,
+    YieldExprOutsideOfCoroutine,
+};
+use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
+use crate::TupleArgumentsFlag::DontTupleArguments;
+use crate::{
+    cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct, BreakableCtxt,
+    CoroutineTypes, Diverges, FnCtxt, Needs,
+};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_expr_has_type_or_error(
@@ -1315,6 +1306,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // No way to know whether it's diverging because
             // of a `break` or an outer `break` or `return`.
             self.diverges.set(Diverges::Maybe);
+        } else {
+            self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
         }
 
         // If we permit break with a value, then result type is
@@ -1743,6 +1736,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ty::new_error(tcx, guar)
             };
 
+            // Check that the expected field type is WF. Otherwise, we emit no use-site error
+            // in the case of coercions for non-WF fields, which leads to incorrect error
+            // tainting. See issue #126272.
+            self.register_wf_obligation(
+                field_type.into(),
+                field.expr.span,
+                ObligationCauseCode::WellFormed(None),
+            );
+
             // Make sure to give a type to the field even if there's
             // an error, so we can continue type-checking.
             let ty = self.check_expr_with_hint(field.expr, field_type);
@@ -2741,15 +2743,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if let ty::RawPtr(ptr_ty, _) = expr_t.kind()
             && let ty::Adt(adt_def, _) = ptr_ty.kind()
             && let ExprKind::Field(base_expr, _) = expr.kind
-            && adt_def.variants().len() == 1
-            && adt_def
-                .variants()
-                .iter()
-                .next()
-                .unwrap()
-                .fields
-                .iter()
-                .any(|f| f.ident(self.tcx) == field)
+            && let [variant] = &adt_def.variants().raw
+            && variant.fields.iter().any(|f| f.ident(self.tcx) == field)
         {
             err.multipart_suggestion(
                 "to access the field, dereference first",
@@ -3347,18 +3342,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let container = self.lower_ty(container).normalized;
 
-        if let Some(ident_2) = fields.get(1)
-            && !self.tcx.features().offset_of_nested
-        {
-            rustc_session::parse::feature_err(
-                &self.tcx.sess,
-                sym::offset_of_nested,
-                ident_2.span,
-                "only a single ident or integer is stable as the field in offset_of",
-            )
-            .emit();
-        }
-
         let mut field_indices = Vec::with_capacity(fields.len());
         let mut current_container = container;
         let mut fields = fields.into_iter();
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 193dbbbcdf4..548d5a7cc4c 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -9,16 +9,15 @@ use std::slice::from_ref;
 use hir::def::DefKind;
 use hir::pat_util::EnumerateAndAdjustIterator as _;
 use hir::Expr;
-use rustc_lint::LateContext;
-// Export these here so that Clippy can use them.
-pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
-
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{HirId, PatKind};
+use rustc_lint::LateContext;
 use rustc_middle::hir::place::ProjectionKind;
+// Export these here so that Clippy can use them.
+pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{
     self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _,
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 9f3aeacd2c5..6e1b7504626 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,10 +1,9 @@
 use std::cell::OnceCell;
 
-use crate::{errors, FnCtxt, TypeckRootCtxt};
-use rustc_data_structures::{
-    graph::{self, iterate::DepthFirstSearch, vec_graph::VecGraph},
-    unord::{UnordBag, UnordMap, UnordSet},
-};
+use rustc_data_structures::graph::iterate::DepthFirstSearch;
+use rustc_data_structures::graph::vec_graph::VecGraph;
+use rustc_data_structures::graph::{self};
+use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::HirId;
@@ -12,10 +11,12 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_session::lint;
-use rustc_span::DUMMY_SP;
-use rustc_span::{def_id::LocalDefId, Span};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 
+use crate::{errors, FnCtxt, TypeckRootCtxt};
+
 #[derive(Copy, Clone)]
 pub enum DivergingFallbackBehavior {
     /// Always fallback to `()` (aka "always spontaneous decay")
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 87e8afe6dd1..b169f75796b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,8 +1,6 @@
-use crate::callee::{self, DeferredCallResolution};
-use crate::errors::{self, CtorIsPrivate};
-use crate::method::{self, MethodCallee};
-use crate::rvalue_scopes;
-use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
+use std::collections::hash_map::Entry;
+use std::slice;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey};
 use rustc_hir as hir;
@@ -26,9 +24,9 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
+    self, AdtKind, CanonicalUserType, GenericArgKind, GenericArgsRef, GenericParamDefKind,
+    IsIdentity, Ty, TyCtxt, UserArgs, UserSelfTy, UserType,
 };
-use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
@@ -41,37 +39,51 @@ use rustc_trait_selection::traits::{
     self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
 };
 
-use std::collections::hash_map::Entry;
-use std::slice;
+use crate::callee::{self, DeferredCallResolution};
+use crate::errors::{self, CtorIsPrivate};
+use crate::method::{self, MethodCallee};
+use crate::{rvalue_scopes, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Produces warning on the given node, if the current point in the
     /// function is unreachable, and there hasn't been another warning.
     pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) {
-        // FIXME: Combine these two 'if' expressions into one once
-        // let chains are implemented
-        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
-            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
-            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
-            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
-            if !span.is_desugaring(DesugaringKind::CondTemporary)
-                && !span.is_desugaring(DesugaringKind::Async)
-                && !orig_span.is_desugaring(DesugaringKind::Await)
-            {
-                self.diverges.set(Diverges::WarnedAlways);
+        let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else {
+            return;
+        };
 
-                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
+        match span.desugaring_kind() {
+            // If span arose from a desugaring of `if` or `while`, then it is the condition
+            // itself, which diverges, that we are about to lint on. This gives suboptimal
+            // diagnostics. Instead, stop here so that the `if`- or `while`-expression's
+            // block is linted instead.
+            Some(DesugaringKind::CondTemporary) => return,
 
-                let msg = format!("unreachable {kind}");
-                self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
-                    lint.primary_message(msg.clone());
-                    lint.span_label(span, msg).span_label(
-                        orig_span,
-                        custom_note.unwrap_or("any code following this expression is unreachable"),
-                    );
-                })
-            }
+            // Don't lint if the result of an async block or async function is `!`.
+            // This does not affect the unreachable lints *within* the body.
+            Some(DesugaringKind::Async) => return,
+
+            // Don't lint *within* the `.await` operator, since that's all just desugaring
+            // junk. We only want to lint if there is a subsequent expression after the
+            // `.await` operator.
+            Some(DesugaringKind::Await) => return,
+
+            _ => {}
         }
+
+        // Don't warn twice.
+        self.diverges.set(Diverges::WarnedAlways);
+
+        debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
+
+        let msg = format!("unreachable {kind}");
+        self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
+            lint.primary_message(msg.clone());
+            lint.span_label(span, msg).span_label(
+                orig_span,
+                custom_note.unwrap_or("any code following this expression is unreachable"),
+            );
+        })
     }
 
     /// Resolves type and const variables in `ty` if possible. Unlike the infcx
@@ -392,8 +404,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         code: traits::ObligationCauseCode<'tcx>,
     ) {
         if !ty.references_error() {
-            let tail =
-                self.tcx.struct_tail_with_normalize(ty, |ty| self.normalize(span, ty), || {});
+            let tail = self.tcx.struct_tail_raw(
+                ty,
+                |ty| {
+                    if self.next_trait_solver() {
+                        self.try_structurally_resolve_type(span, ty)
+                    } else {
+                        self.normalize(span, ty)
+                    }
+                },
+                || {},
+            );
             // Sized types have static alignment, and so do slices.
             if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) {
                 // Nothing else is required here.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 8e35efa53ae..130fd130ec8 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -1,13 +1,15 @@
-use crate::FnCtxt;
+use std::ops::ControlFlow;
+
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use rustc_span::{symbol::kw, Span};
+use rustc_span::symbol::kw;
+use rustc_span::Span;
 use rustc_trait_selection::traits;
 
-use std::ops::ControlFlow;
+use crate::FnCtxt;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn adjust_fulfillment_error_for_expr_obligation(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index 566d407d23c..78895689433 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
@@ -1,7 +1,8 @@
 use core::cmp::Ordering;
+use std::cmp;
+
 use rustc_index::IndexVec;
 use rustc_middle::ty::error::TypeError;
-use std::cmp;
 
 rustc_index::newtype_index! {
     #[orderable]
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 7c96a991bed..89e7227eda2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,26 +1,12 @@
-use crate::coercion::CoerceMany;
-use crate::errors::SuggestPtrNullMut;
-use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
-use crate::fn_ctxt::infer::FnCall;
-use crate::gather_locals::Declaration;
-use crate::method::probe::IsSuggestion;
-use crate::method::probe::Mode::MethodCall;
-use crate::method::probe::ProbeScope::TraitsInScope;
-use crate::method::MethodCallee;
-use crate::TupleArgumentsFlag::*;
-use crate::{errors, Expectation::*};
-use crate::{
-    struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs,
-    TupleArgumentsFlag,
-};
+use std::{iter, mem};
+
 use itertools::Itertools;
-use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag,
-    ErrorGuaranteed, MultiSpan, StashKey,
+    a_or_an, display_list_with_comma_and, pluralize, Applicability, Diag, ErrorGuaranteed,
+    MultiSpan, StashKey,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
@@ -29,21 +15,34 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
 use rustc_hir_analysis::check::potentially_plural_count;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_index::IndexVec;
-use rustc_infer::infer::TypeTrace;
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
+use {rustc_ast as ast, rustc_hir as hir};
 
-use std::iter;
-use std::mem;
+use crate::coercion::CoerceMany;
+use crate::errors::SuggestPtrNullMut;
+use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
+use crate::fn_ctxt::infer::FnCall;
+use crate::gather_locals::Declaration;
+use crate::method::probe::IsSuggestion;
+use crate::method::probe::Mode::MethodCall;
+use crate::method::probe::ProbeScope::TraitsInScope;
+use crate::method::MethodCallee;
+use crate::Expectation::*;
+use crate::TupleArgumentsFlag::*;
+use crate::{
+    errors, struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs,
+    TupleArgumentsFlag,
+};
 
 #[derive(Clone, Copy, Default)]
 pub enum DivergingBlockBehavior {
@@ -1141,8 +1140,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 .get(arg_idx + 1)
                                 .map(|&(_, sp)| sp)
                                 .unwrap_or_else(|| {
-                                    // Subtract one to move before `)`
-                                    call_expr.span.with_lo(call_expr.span.hi() - BytePos(1))
+                                    // Try to move before `)`. Note that `)` here is not necessarily
+                                    // the latin right paren, it could be a Unicode-confusable that
+                                    // looks like a `)`, so we must not use `- BytePos(1)`
+                                    // manipulations here.
+                                    self.tcx().sess.source_map().end_point(call_expr.span)
                                 });
 
                             // Include next comma
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index 90dd5f73586..be4db2934b7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -1,12 +1,14 @@
 //! A utility module to inspect currently ambiguous obligations in the current context.
 
-use crate::FnCtxt;
 use rustc_infer::traits::{self, ObligationCause};
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_span::Span;
-use rustc_trait_selection::solve::inspect::ProofTreeInferCtxtExt;
-use rustc_trait_selection::solve::inspect::{InspectConfig, InspectGoal, ProofTreeVisitor};
+use rustc_trait_selection::solve::inspect::{
+    InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
+};
+
+use crate::FnCtxt;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Returns a list of all obligations whose self type has been unified
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 39d73dae015..33f80dd3773 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -5,13 +5,11 @@ mod checks;
 mod inspect_obligations;
 mod suggestions;
 
-use rustc_errors::DiagCtxtHandle;
+use std::cell::{Cell, RefCell};
+use std::ops::Deref;
 
-use crate::coercion::DynamicCoerceMany;
-use crate::fallback::DivergingFallbackBehavior;
-use crate::fn_ctxt::checks::DivergingBlockBehavior;
-use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
 use hir::def_id::CRATE_DEF_ID;
+use rustc_errors::DiagCtxtHandle;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
@@ -24,8 +22,10 @@ use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
 use rustc_trait_selection::error_reporting::TypeErrCtxt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
 
-use std::cell::{Cell, RefCell};
-use std::ops::Deref;
+use crate::coercion::DynamicCoerceMany;
+use crate::fallback::DivergingFallbackBehavior;
+use crate::fn_ctxt::checks::DivergingBlockBehavior;
+use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
 
 /// The `FnCtxt` stores type-checking context needed to type-check bodies of
 /// functions, closures, and `const`s, including performing type inference
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index fe7495deb2b..6b4edcd95d9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,20 +1,12 @@
-use super::FnCtxt;
-
-use crate::errors;
-use crate::fluent_generated as fluent;
-use crate::fn_ctxt::rustc_span::BytePos;
-use crate::hir::is_range_literal;
-use crate::method::probe;
-use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use core::cmp::min;
 use core::iter;
+
 use hir::def_id::LocalDefId;
 use rustc_ast::util::parser::{ExprPrecedence, PREC_UNAMBIGUOUS};
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::{Applicability, Diag, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
-use rustc_hir::def::{CtorKind, CtorOf, DefKind};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
@@ -26,8 +18,10 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, suggest_constraining_type_params, Article, Binder};
-use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Upcast};
+use rustc_middle::ty::{
+    self, suggest_constraining_type_params, Article, Binder, IsSuggestable, Ty, TyCtxt,
+    TypeVisitableExt, Upcast,
+};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
@@ -38,6 +32,13 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
+use super::FnCtxt;
+use crate::fn_ctxt::rustc_span::BytePos;
+use crate::hir::is_range_literal;
+use crate::method::probe;
+use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
+use crate::{errors, fluent_generated as fluent};
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
         self.typeck_results
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 13e4b625e2d..0fd450e869a 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -1,13 +1,13 @@
-use crate::FnCtxt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, PatKind};
 use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::ty::Ty;
-use rustc_middle::ty::UserType;
+use rustc_middle::ty::{Ty, UserType};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
+use crate::FnCtxt;
+
 /// Provides context for checking patterns in declarations. More specifically this
 /// allows us to infer array types if the pattern is irrefutable and allows us to infer
 /// the size of the array. See issue #76342.
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 0389c06c312..a9c929e76d5 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -1,5 +1,6 @@
 use hir::HirId;
-use rustc_errors::{codes::*, struct_span_code_err};
+use rustc_errors::codes::*;
+use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_middle::bug;
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 2c793664509..758a1cefe63 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -44,16 +44,9 @@ mod writeback;
 
 pub use coercion::can_coerce;
 use fn_ctxt::FnCtxt;
-use typeck_root_ctxt::TypeckRootCtxt;
-
-use crate::check::check_fn;
-use crate::coercion::DynamicCoerceMany;
-use crate::diverges::Diverges;
-use crate::expectation::Expectation;
-use crate::fn_ctxt::LoweredTy;
-use crate::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, ErrorGuaranteed};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::Visitor;
@@ -67,6 +60,14 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::config;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
+use typeck_root_ctxt::TypeckRootCtxt;
+
+use crate::check::check_fn;
+use crate::coercion::DynamicCoerceMany;
+use crate::diverges::Diverges;
+use crate::expectation::Expectation;
+use crate::fn_ctxt::LoweredTy;
+use crate::gather_locals::GatherLocalsVisitor;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
@@ -264,11 +265,10 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
             Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
             | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
                 asm.operands.iter().find_map(|(op, _op_sp)| match op {
-                    hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
-                        // Inline assembly constants must be integers.
-                        Some(fcx.next_int_var())
-                    }
-                    hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
+                    hir::InlineAsmOperand::Const { anon_const }
+                    | hir::InlineAsmOperand::SymFn { anon_const }
+                        if anon_const.hir_id == id =>
+                    {
                         Some(fcx.next_ty_var(span))
                     }
                     _ => None,
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index e70431a68ff..e0c0adac076 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -1,6 +1,5 @@
-use super::{probe, MethodCallee};
+use std::ops::Deref;
 
-use crate::{callee, FnCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
@@ -12,17 +11,20 @@ use rustc_hir_analysis::hir_ty_lowering::{
 };
 use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
 use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
-use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::adjustment::{
+    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
+};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, UserArgs, UserType,
+    self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, UserArgs,
+    UserType,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
-use std::ops::Deref;
+use super::{probe, MethodCallee};
+use crate::{callee, FnCtxt};
 
 struct ConfirmContext<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -268,6 +270,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
 
             probe::ObjectPick => {
                 let trait_def_id = pick.item.container_id(self.tcx);
+
+                // This shouldn't happen for non-region error kinds, but may occur
+                // when we have error regions. Specifically, since we canonicalize
+                // during method steps, we may successfully deref when we assemble
+                // the pick, but fail to deref when we try to extract the object
+                // type from the pick during confirmation. This is fine, we're basically
+                // already doomed by this point.
+                if self_ty.references_error() {
+                    return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
+                }
+
                 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
                     // The object data has no entry for the Self
                     // Type. For the purposes of this method call, we
@@ -641,17 +654,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
 
         // must be exactly one trait ref or we'd get an ambig error etc
-        if upcast_trait_refs.len() != 1 {
+        let [upcast_trait_ref] = upcast_trait_refs.as_slice() else {
             span_bug!(
                 self.span,
                 "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
                 source_trait_ref,
                 target_trait_def_id,
                 upcast_trait_refs
-            );
-        }
+            )
+        };
 
-        upcast_trait_refs.into_iter().next().unwrap()
+        *upcast_trait_ref
     }
 
     fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index daf4ef5cdb3..d6110ab94c1 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -7,9 +7,6 @@ mod prelude_edition_lints;
 pub mod probe;
 mod suggest;
 
-pub use self::MethodError::*;
-
-use crate::FnCtxt;
 use rustc_errors::{Applicability, Diag, SubdiagMessage};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
@@ -17,8 +14,9 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
-use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::ty::{
+    self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
@@ -26,6 +24,8 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, NormalizeExt};
 
 use self::probe::{IsSuggestion, ProbeScope};
+pub use self::MethodError::*;
+use crate::FnCtxt;
 
 pub fn provide(providers: &mut Providers) {
     probe::provide(providers);
diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index 3ee10f74d98..0a4c3dc8af9 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -1,20 +1,20 @@
-use crate::method::probe::{self, Pick};
-use crate::FnCtxt;
+use std::fmt::Write;
 
 use hir::def_id::DefId;
-use hir::HirId;
-use hir::ItemKind;
+use hir::{HirId, ItemKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty};
-use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
+use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS};
 use rustc_span::symbol::kw::{Empty, Underscore};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
-use std::fmt::Write;
+
+use crate::method::probe::{self, Pick};
+use crate::FnCtxt;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(super) fn lint_edition_dependent_dot_call(
@@ -35,6 +35,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (prelude_or_array_lint, edition) = match segment.ident.name {
             // `try_into` was added to the prelude in Rust 2021.
             sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
+            // `Future::poll` was added to the prelude in Rust 2024.
+            sym::poll
+                // We check that the self type is `Pin<&mut _>` to avoid false positives for this common name.
+                if !span.at_least_rust_2024()
+                    && let ty::Adt(adt_def, args) = self_ty.kind()
+                    && self.tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin)
+                    && let ty::Ref(_, _, ty::Mutability::Mut) =
+                        args[0].as_type().unwrap().kind() =>
+            {
+                (RUST_2024_PRELUDE_COLLISIONS, "2024")
+            }
+            // `IntoFuture::into_future` was added to the prelude in Rust 2024.
+            sym::into_future if !span.at_least_rust_2024() => {
+                (RUST_2024_PRELUDE_COLLISIONS, "2024")
+            }
             // `into_iter` wasn't added to the prelude,
             // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
             // before Rust 2021, which results in the same problem.
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index ae34ddeaa87..28f537c87c4 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1,58 +1,46 @@
-use super::suggest;
-use super::CandidateSource;
-use super::MethodError;
-use super::NoMatchData;
+use std::cell::{Cell, RefCell};
+use std::cmp::max;
+use std::iter;
+use std::ops::Deref;
 
-use crate::FnCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
 use rustc_hir_analysis::autoderef::{self, Autoderef};
-use rustc_infer::infer::canonical::OriginalQueryValues;
-use rustc_infer::infer::canonical::{Canonical, QueryResponse};
-use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
+use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::middle::stability;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::AssocItem;
-use rustc_middle::ty::AssocItemContainer;
-use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::Upcast;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::ty::{
+    self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind,
+    ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
-use rustc_span::def_id::DefId;
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::edit_distance::{
     edit_distance_with_substrings, find_best_match_for_name_with_substrings,
 };
-use rustc_span::symbol::sym;
-use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
 use rustc_trait_selection::traits::query::method_autoderef::{
-    CandidateStep, MethodAutoderefStepsResult,
+    CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult,
 };
 use rustc_trait_selection::traits::query::CanonicalTyGoal;
-use rustc_trait_selection::traits::ObligationCtxt;
-use rustc_trait_selection::traits::{self, ObligationCause};
-use std::cell::Cell;
-use std::cell::RefCell;
-use std::cmp::max;
-use std::iter;
-use std::ops::Deref;
-
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
 use smallvec::{smallvec, SmallVec};
 
 use self::CandidateKind::*;
 pub use self::PickKind::*;
+use super::{suggest, CandidateSource, MethodError, NoMatchData};
+use crate::FnCtxt;
 
 /// Boolean flag used to indicate if this search is for a suggestion
 /// or not. If true, we can allow ambiguity and so forth.
@@ -786,18 +774,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         // instantiation that replaces `Self` with the object type itself. Hence,
         // a `&self` method will wind up with an argument type like `&dyn Trait`.
         let trait_ref = principal.with_self_ty(self.tcx, self_ty);
-        self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
-            this.push_candidate(
-                Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] },
-                true,
-            );
-        });
+        self.assemble_candidates_for_bounds(
+            traits::supertraits(self.tcx, trait_ref),
+            |this, new_trait_ref, item| {
+                this.push_candidate(
+                    Candidate {
+                        item,
+                        kind: ObjectCandidate(new_trait_ref),
+                        import_ids: smallvec![],
+                    },
+                    true,
+                );
+            },
+        );
     }
 
     #[instrument(level = "debug", skip(self))]
     fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
-        // FIXME: do we want to commit to this behavior for param bounds?
-
         let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
             let bound_predicate = predicate.kind();
             match bound_predicate.skip_binder() {
@@ -818,7 +811,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             }
         });
 
-        self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
+        self.assemble_candidates_for_bounds(bounds, |this, poly_trait_ref, item| {
             this.push_candidate(
                 Candidate {
                     item,
@@ -832,15 +825,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     // Do a search through a list of bounds, using a callback to actually
     // create the candidates.
-    fn elaborate_bounds<F>(
+    fn assemble_candidates_for_bounds<F>(
         &mut self,
         bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
         mut mk_cand: F,
     ) where
         F: for<'b> FnMut(&mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::AssocItem),
     {
-        let tcx = self.tcx;
-        for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
+        for bound_trait_ref in bounds {
             debug!("elaborate_bounds(bound_trait_ref={:?})", bound_trait_ref);
             for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
                 if !self.has_applicable_self(&item) {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index da3ac2fea98..61287d98676 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3,49 +3,45 @@
 
 // ignore-tidy-filelength
 
-use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
-use crate::Expectation;
-use crate::FnCtxt;
 use core::ops::ControlFlow;
+use std::borrow::Cow;
+
 use hir::Expr;
 use rustc_ast::ast::Mutability;
 use rustc_attr::parse_confusables;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey,
-};
+use rustc_errors::codes::*;
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::PathSegment;
-use rustc_hir::{self as hir, HirId};
-use rustc_hir::{ExprKind, Node, QPath};
+use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath};
 use rustc_infer::infer::{self, RegionVariableOrigin};
 use rustc_middle::bug;
-use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
+use rustc_middle::ty::fast_reject::{simplify_type, DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::print::{
     with_crate_prefix, with_forced_trimmed_paths, PrintTraitRefExt as _,
 };
-use rustc_middle::ty::IsSuggestable;
-use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::def_id::DefIdSet;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span};
-use rustc_span::{Symbol, DUMMY_SP};
+use rustc_span::{
+    edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, DUMMY_SP,
+};
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     supertraits, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
 };
-use std::borrow::Cow;
 
 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
-use rustc_hir::intravisit::{self, Visitor};
+use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
+use crate::{Expectation, FnCtxt};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -325,19 +321,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     );
                                 };
                             let suggest_for_privacy =
-                                |err: &mut Diag<'_>, mut msg: String, sugg: Vec<String>| {
-                                    if sugg.len() == 1 {
-                                        let msg = format!("\
+                                |err: &mut Diag<'_>, mut msg: String, suggs: Vec<String>| {
+                                    if let [sugg] = suggs.as_slice() {
+                                        err.help(format!("\
                                             trait `{}` provides `{item_name}` is implemented but not reachable",
-                                            sugg[0].trim()
-                                        );
-                                        err.help(msg);
+                                            sugg.trim(),
+                                        ));
                                     } else {
-                                        msg += &format!(" but {} not reachable", pluralize!("is", sugg.len()));
+                                        msg += &format!(" but {} not reachable", pluralize!("is", suggs.len()));
                                         err.span_suggestions(
                                             span,
                                             msg,
-                                            sugg,
+                                            suggs,
                                             Applicability::MaybeIncorrect,
                                         );
                                     }
@@ -2992,11 +2987,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         if local_spans.primary_span().is_some() {
-            let msg = if local_preds.len() == 1 {
+            let msg = if let [local_pred] = local_preds.as_slice() {
                 format!(
                     "an implementation of `{}` might be missing for `{}`",
-                    local_preds[0].trait_ref.print_trait_sugared(),
-                    local_preds[0].self_ty()
+                    local_pred.trait_ref.print_trait_sugared(),
+                    local_pred.self_ty()
                 )
             } else {
                 format!(
@@ -3038,11 +3033,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         if foreign_spans.primary_span().is_some() {
-            let msg = if foreign_preds.len() == 1 {
+            let msg = if let [foreign_pred] = foreign_preds.as_slice() {
                 format!(
                     "the foreign item type `{}` doesn't implement `{}`",
-                    foreign_preds[0].self_ty(),
-                    foreign_preds[0].trait_ref.print_trait_sugared()
+                    foreign_pred.self_ty(),
+                    foreign_pred.trait_ref.print_trait_sugared()
                 )
             } else {
                 format!(
@@ -3392,26 +3387,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
 
             self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| {
-                let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| {
+                let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, suggs: Vec<_>| {
                     msg += &format!(
                         "; perhaps you want to import {one_of}",
-                        one_of = if sugg.len() == 1 { "it" } else { "one of them" },
+                        one_of = if suggs.len() == 1 { "it" } else { "one of them" },
                     );
-                    err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
+                    err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
                 };
-                let suggest_for_privacy = |err: &mut Diag<'_>, sugg: Vec<String>| {
+                let suggest_for_privacy = |err: &mut Diag<'_>, suggs: Vec<String>| {
                     let msg = format!(
                         "{this_trait_is} implemented but not reachable",
-                        this_trait_is = if sugg.len() == 1 {
-                            format!("trait `{}` which provides `{item_name}` is", sugg[0].trim())
+                        this_trait_is = if let [sugg] = suggs.as_slice() {
+                            format!("trait `{}` which provides `{item_name}` is", sugg.trim())
                         } else {
                             format!("the following traits which provide `{item_name}` are")
                         }
                     );
-                    if sugg.len() == 1 {
+                    if suggs.len() == 1 {
                         err.help(msg);
                     } else {
-                        err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
+                        err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
                     }
                 };
                 if accessible_sugg.is_empty() {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 7b5845388d4..c54f6cfd099 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -1,12 +1,8 @@
 //! Code related to processing overloaded binary and unary operators.
 
-use super::method::MethodCallee;
-use super::FnCtxt;
-use crate::Expectation;
-use rustc_ast as ast;
 use rustc_data_structures::packed::Pu128;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag};
-use rustc_hir as hir;
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, Diag};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
@@ -21,6 +17,11 @@ use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
 use rustc_type_ir::TyKind::*;
+use {rustc_ast as ast, rustc_hir as hir};
+
+use super::method::MethodCallee;
+use super::FnCtxt;
+use crate::Expectation;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 8afc6a48dfc..c4f74adb420 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,9 +1,11 @@
-use crate::gather_locals::DeclOrigin;
-use crate::{errors, FnCtxt, LoweredTy};
+use std::cmp;
+use std::collections::hash_map::Entry::{Occupied, Vacant};
+
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
+    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
@@ -12,7 +14,8 @@ use rustc_infer::infer;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
-use rustc_session::{lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, parse::feature_err};
+use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
+use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::Spanned;
@@ -23,10 +26,9 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 use ty::VariantDef;
 
-use std::cmp;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-
 use super::report_unexpected_variant_res;
+use crate::gather_locals::DeclOrigin;
+use crate::{errors, FnCtxt, LoweredTy};
 
 const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
 This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 515e1b5ed0e..ad04b6b8b1d 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,16 +1,18 @@
-use crate::method::MethodCallee;
-use crate::{FnCtxt, PlaceOp};
-use rustc_ast as ast;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir_analysis::autoderef::Autoderef;
 use rustc_infer::infer::InferOk;
 use rustc_middle::span_bug;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCoercion};
-use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::adjustment::{
+    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, OverloadedDeref,
+    PointerCoercion,
+};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use {rustc_ast as ast, rustc_hir as hir};
+
+use crate::method::MethodCallee;
+use crate::{FnCtxt, PlaceOp};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 805f36d9b97..f22a13d292e 100644
--- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
@@ -1,4 +1,3 @@
-use super::FnCtxt;
 use hir::def_id::DefId;
 use hir::Node;
 use rustc_hir as hir;
@@ -6,6 +5,8 @@ use rustc_middle::bug;
 use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
 use rustc_middle::ty::RvalueScopes;
 
+use super::FnCtxt;
+
 /// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
 /// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
 /// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index c99e8a7fe8e..a43164589b5 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -1,4 +1,5 @@
-use super::callee::DeferredCallResolution;
+use std::cell::RefCell;
+use std::ops::Deref;
 
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
@@ -15,8 +16,7 @@ use rustc_trait_selection::traits::{
     self, FulfillmentError, PredicateObligation, TraitEngine, TraitEngineExt as _,
 };
 
-use std::cell::RefCell;
-use std::ops::Deref;
+use super::callee::DeferredCallResolution;
 
 /// Data shared between a "typeck root" and its nested bodies,
 /// e.g. closures defined within the function. For example:
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 466397817da..55f002291f0 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -30,9 +30,9 @@
 //! then mean that all later passes would have to check for these figments
 //! and report an error, and it just seems like more mess in the end.)
 
-use super::FnCtxt;
+use std::iter;
 
-use crate::expr_use_visitor as euv;
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::{ExtendUnord, UnordSet};
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir as hir;
@@ -49,14 +49,12 @@ use rustc_middle::ty::{
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
-use rustc_span::sym;
-use rustc_span::{BytePos, Pos, Span, Symbol};
-use rustc_trait_selection::infer::InferCtxtExt;
-
-use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_span::{sym, BytePos, Pos, Span, Symbol};
 use rustc_target::abi::FIRST_VARIANT;
+use rustc_trait_selection::infer::InferCtxtExt;
 
-use std::iter;
+use super::FnCtxt;
+use crate::expr_use_visitor as euv;
 
 /// Describe the relationship between the paths of two places
 /// eg:
@@ -221,7 +219,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `async-await/async-closures/force-move-due-to-inferred-kind.rs`.
         //
         // 2. If the coroutine-closure is forced to be `FnOnce` due to the way it
-        // uses its upvars, but not *all* upvars would force the closure to `FnOnce`.
+        // uses its upvars (e.g. it consumes a non-copy value), but not *all* upvars
+        // would force the closure to `FnOnce`.
         // See the test: `async-await/async-closures/force-move-due-to-actually-fnonce.rs`.
         //
         // This would lead to an impossible to satisfy situation, since `AsyncFnOnce`
@@ -229,11 +228,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // we force the inner coroutine to also be `move`. This only matters for
         // coroutine-closures that are `move` since otherwise they themselves will
         // be borrowing from the outer environment, so there's no self-borrows occuring.
-        //
-        // One *important* note is that we do a call to `process_collected_capture_information`
-        // to eagerly test whether the coroutine would end up `FnOnce`, but we do this
-        // *before* capturing all the closure args by-value below, since that would always
-        // cause the analysis to return `FnOnce`.
         if let UpvarArgs::Coroutine(..) = args
             && let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
                 self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
@@ -248,19 +242,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 capture_clause = hir::CaptureBy::Value { move_kw };
             }
             // (2.) The way that the closure uses its upvars means it's `FnOnce`.
-            else if let (_, ty::ClosureKind::FnOnce, _) = self
-                .process_collected_capture_information(
-                    capture_clause,
-                    &delegate.capture_information,
-                )
-            {
+            else if self.coroutine_body_consumes_upvars(closure_def_id, body) {
                 capture_clause = hir::CaptureBy::Value { move_kw };
             }
         }
 
         // As noted in `lower_coroutine_body_with_moved_arguments`, we default the capture mode
         // to `ByRef` for the `async {}` block internal to async fns/closure. This means
-        // that we would *not* be moving all of the parameters into the async block by default.
+        // that we would *not* be moving all of the parameters into the async block in all cases.
+        // For example, when one of the arguments is `Copy`, we turn a consuming use into a copy of
+        // a reference, so for `async fn x(t: i32) {}`, we'd only take a reference to `t`.
         //
         // We force all of these arguments to be captured by move before we do expr use analysis.
         //
@@ -537,6 +528,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Determines whether the body of the coroutine uses its upvars in a way that
+    /// consumes (i.e. moves) the value, which would force the coroutine to `FnOnce`.
+    /// In a more detailed comment above, we care whether this happens, since if
+    /// this happens, we want to force the coroutine to move all of the upvars it
+    /// would've borrowed from the parent coroutine-closure.
+    ///
+    /// This only really makes sense to be called on the child coroutine of a
+    /// coroutine-closure.
+    fn coroutine_body_consumes_upvars(
+        &self,
+        coroutine_def_id: LocalDefId,
+        body: &'tcx hir::Body<'tcx>,
+    ) -> bool {
+        // This block contains argument capturing details. Since arguments
+        // aren't upvars, we do not care about them for determining if the
+        // coroutine body actually consumes its upvars.
+        let hir::ExprKind::Block(&hir::Block { expr: Some(body), .. }, None) = body.value.kind
+        else {
+            bug!();
+        };
+        // Specifically, we only care about the *real* body of the coroutine.
+        // We skip out into the drop-temps within the block of the body in order
+        // to skip over the args of the desugaring.
+        let hir::ExprKind::DropTemps(body) = body.kind else {
+            bug!();
+        };
+
+        let mut delegate = InferBorrowKind {
+            closure_def_id: coroutine_def_id,
+            capture_information: Default::default(),
+            fake_reads: Default::default(),
+        };
+
+        let _ = euv::ExprUseVisitor::new(
+            &FnCtxt::new(self, self.tcx.param_env(coroutine_def_id), coroutine_def_id),
+            &mut delegate,
+        )
+        .consume_expr(body);
+
+        let (_, kind, _) = self.process_collected_capture_information(
+            hir::CaptureBy::Ref,
+            &delegate.capture_information,
+        );
+
+        matches!(kind, ty::ClosureKind::FnOnce)
+    }
+
     // Returns a list of `Ty`s for each upvar.
     fn final_upvar_tys(&self, closure_id: LocalDefId) -> Vec<Ty<'tcx>> {
         self.typeck_results
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 4ef7f37b309..0327a3097ec 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -2,7 +2,8 @@
 // unresolved type variables and replaces "ty_var" types with their
 // generic parameters.
 
-use crate::FnCtxt;
+use std::mem;
+
 use rustc_data_structures::unord::ExtendUnord;
 use rustc_errors::{ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
@@ -13,14 +14,13 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::TypeSuperFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_trait_selection::solve;
 
-use std::mem;
+use crate::FnCtxt;
 
 ///////////////////////////////////////////////////////////////////////////
 // Entry point
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 41caa5d4765..b29ba59c9f3 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -33,12 +33,12 @@
 //! fn baz() { foo(); }
 //! ```
 
-use crate::errors;
-use rustc_ast as ast;
+use std::env;
+use std::fs::{self, File};
+use std::io::{BufWriter, Write};
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING};
-use rustc_graphviz as dot;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::dep_graph::{
@@ -49,10 +49,10 @@ use rustc_middle::ty::TyCtxt;
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use std::env;
-use std::fs::{self, File};
-use std::io::{BufWriter, Write};
 use tracing::debug;
+use {rustc_ast as ast, rustc_graphviz as dot, rustc_hir as hir};
+
+use crate::errors;
 
 #[allow(missing_docs)]
 pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs
index e94a7fb876b..f8910030634 100644
--- a/compiler/rustc_incremental/src/errors.rs
+++ b/compiler/rustc_incremental/src/errors.rs
@@ -1,7 +1,9 @@
-use rustc_macros::Diagnostic;
-use rustc_span::{symbol::Ident, Span, Symbol};
 use std::path::{Path, PathBuf};
 
+use rustc_macros::Diagnostic;
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
+
 #[derive(Diagnostic)]
 #[diag(incremental_unrecognized_depnode)]
 pub struct UnrecognizedDepNode {
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 76e3c0682de..fcdcb08eed6 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -12,14 +12,10 @@ mod assert_dep_graph;
 mod errors;
 mod persist;
 
-pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
-pub use persist::finalize_session_directory;
-pub use persist::in_incr_comp_dir;
-pub use persist::in_incr_comp_dir_sess;
-pub use persist::load_query_result_cache;
-pub use persist::save_dep_graph;
-pub use persist::save_work_product_index;
-pub use persist::setup_dep_graph;
-pub use persist::LoadResult;
+pub use persist::{
+    copy_cgu_workproduct_to_incr_comp_cache_dir, finalize_session_directory, in_incr_comp_dir,
+    in_incr_comp_dir_sess, load_query_result_cache, save_dep_graph, save_work_product_index,
+    setup_dep_graph, LoadResult,
+};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 2a0d681fa37..1e02324f404 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -19,14 +19,11 @@
 //! Errors are reported if we are in the suitable configuration but
 //! the required condition is not met.
 
-use crate::errors;
 use rustc_ast::{self as ast, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::unord::UnordSet;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit;
-use rustc_hir::Node as HirNode;
-use rustc_hir::{ImplItemKind, ItemKind as HirItem, TraitItemKind};
+use rustc_hir::{intravisit, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind};
 use rustc_middle::dep_graph::{label_strs, DepNode, DepNodeExt};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
@@ -35,6 +32,8 @@ use rustc_span::Span;
 use thin_vec::ThinVec;
 use tracing::debug;
 
+use crate::errors;
+
 const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk;
 const EXCEPT: Symbol = sym::except;
 const CFG: Symbol = sym::cfg;
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 303785bdb22..174414d0c85 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -9,18 +9,19 @@
 //! compiler versions don't change frequently for the typical user, being
 //! conservative here practically has no downside.
 
-use crate::errors;
+use std::borrow::Cow;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+use std::{env, fs};
+
 use rustc_data_structures::memmap::Mmap;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encoder;
 use rustc_session::Session;
-use std::borrow::Cow;
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
 use tracing::debug;
 
+use crate::errors;
+
 /// The first few bytes of files generated by incremental compilation.
 const FILE_MAGIC: &[u8] = b"RSIC";
 
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 9afea3d66b0..5f85e622e89 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -103,30 +103,27 @@
 //! unsupported file system and emit a warning in that case. This is not yet
 //! implemented.
 
-use crate::errors;
-use rustc_data_structures::base_n;
-use rustc_data_structures::base_n::BaseNString;
-use rustc_data_structures::base_n::ToBaseN;
-use rustc_data_structures::base_n::CASE_INSENSITIVE;
-use rustc_data_structures::flock;
+use std::fs as std_fs;
+use std::io::{self, ErrorKind};
+use std::path::{Path, PathBuf};
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+
+use rand::{thread_rng, RngCore};
+use rustc_data_structures::base_n::{BaseNString, ToBaseN, CASE_INSENSITIVE};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
+use rustc_data_structures::{base_n, flock};
 use rustc_errors::ErrorGuaranteed;
 use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
 use rustc_middle::bug;
 use rustc_session::config::CrateType;
 use rustc_session::output::{collect_crate_types, find_crate_name};
 use rustc_session::{Session, StableCrateId};
-
-use std::fs as std_fs;
-use std::io::{self, ErrorKind};
-use std::path::{Path, PathBuf};
-use std::time::{Duration, SystemTime, UNIX_EPOCH};
-
-use rand::{thread_rng, RngCore};
 use tracing::debug;
 
+use crate::errors;
+
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index af667a57ce1..18088a10dd0 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -1,6 +1,8 @@
 //! Code to load the dep-graph from files.
 
-use crate::errors;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::unord::UnordMap;
 use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProductMap};
@@ -10,15 +12,13 @@ use rustc_serialize::Decodable;
 use rustc_session::config::IncrementalStateAssertion;
 use rustc_session::Session;
 use rustc_span::ErrorGuaranteed;
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
 use tracing::{debug, warn};
 
 use super::data::*;
-use super::file_format;
 use super::fs::*;
 use super::save::build_dep_graph;
-use super::work_product;
+use super::{file_format, work_product};
+use crate::errors;
 
 #[derive(Debug)]
 /// Represents the result of an attempt to load incremental compilation data.
diff --git a/compiler/rustc_incremental/src/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs
index 94c05f4a2c8..a529b1dcec0 100644
--- a/compiler/rustc_incremental/src/persist/mod.rs
+++ b/compiler/rustc_incremental/src/persist/mod.rs
@@ -10,12 +10,7 @@ mod load;
 mod save;
 mod work_product;
 
-pub use fs::finalize_session_directory;
-pub use fs::in_incr_comp_dir;
-pub use fs::in_incr_comp_dir_sess;
-pub use load::load_query_result_cache;
-pub use load::setup_dep_graph;
-pub use load::LoadResult;
-pub use save::save_dep_graph;
-pub use save::save_work_product_index;
+pub use fs::{finalize_session_directory, in_incr_comp_dir, in_incr_comp_dir_sess};
+pub use load::{load_query_result_cache, setup_dep_graph, LoadResult};
+pub use save::{save_dep_graph, save_work_product_index};
 pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 3bf582bd26c..58a03cb8b30 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -1,5 +1,6 @@
-use crate::assert_dep_graph::assert_dep_graph;
-use crate::errors;
+use std::fs;
+use std::sync::Arc;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::join;
 use rustc_middle::dep_graph::{
@@ -9,15 +10,13 @@ use rustc_middle::ty::TyCtxt;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encodable as RustcEncodable;
 use rustc_session::Session;
-use std::fs;
-use std::sync::Arc;
 use tracing::debug;
 
 use super::data::*;
-use super::dirty_clean;
-use super::file_format;
 use super::fs::*;
-use super::work_product;
+use super::{dirty_clean, file_format, work_product};
+use crate::assert_dep_graph::assert_dep_graph;
+use crate::errors;
 
 /// Saves and writes the [`DepGraph`] to the file system.
 ///
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index e230da9dfb1..048981f0d5c 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -2,16 +2,18 @@
 //!
 //! [work products]: WorkProduct
 
-use crate::errors;
-use crate::persist::fs::*;
+use std::fs as std_fs;
+use std::path::Path;
+
 use rustc_data_structures::unord::UnordMap;
 use rustc_fs_util::link_or_copy;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_session::Session;
-use std::fs as std_fs;
-use std::path::Path;
 use tracing::debug;
 
+use crate::errors;
+use crate::persist::fs::*;
+
 /// Copies a CGU work product to the incremental compilation directory, so next compilation can
 /// find and reuse it.
 pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index e37af6610dd..506afbae40c 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -1,21 +1,16 @@
-use std::fmt;
-use std::iter;
 use std::marker::PhantomData;
-use std::mem;
 use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl};
 use std::rc::Rc;
-use std::slice;
+use std::{fmt, iter, mem, slice};
 
 use arrayvec::ArrayVec;
-use smallvec::{smallvec, SmallVec};
-
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_Generic, Encodable_Generic};
+use smallvec::{smallvec, SmallVec};
+use Chunk::*;
 
 use crate::{Idx, IndexVec};
 
-use Chunk::*;
-
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index 351d62feed9..066aa46e350 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -2,6 +2,7 @@ use super::*;
 
 extern crate test;
 use std::hint::black_box;
+
 use test::Bencher;
 
 #[test]
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index 0c1180b3e98..be028feca60 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -1,7 +1,6 @@
 use std::iter::Step;
 use std::marker::PhantomData;
-use std::ops::RangeBounds;
-use std::ops::{Bound, Range};
+use std::ops::{Bound, Range, RangeBounds};
 
 use smallvec::SmallVec;
 
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index b775ae1f5e9..b5e4f02a8d1 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -12,9 +12,10 @@ mod idx;
 mod slice;
 mod vec;
 
-pub use {idx::Idx, slice::IndexSlice, vec::IndexVec};
-
+pub use idx::Idx;
 pub use rustc_index_macros::newtype_index;
+pub use slice::IndexSlice;
+pub use vec::IndexVec;
 
 /// Type size assertion. The first argument is a type and the second argument is its expected size.
 ///
diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs
index 0663c7247de..3205ca3f40b 100644
--- a/compiler/rustc_index/src/slice.rs
+++ b/compiler/rustc_index/src/slice.rs
@@ -1,9 +1,6 @@
-use std::{
-    fmt,
-    marker::PhantomData,
-    ops::{Index, IndexMut},
-    slice,
-};
+use std::marker::PhantomData;
+use std::ops::{Index, IndexMut};
+use std::{fmt, slice};
 
 use crate::{Idx, IndexVec};
 
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 346ce945bf9..7438c97eb58 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -1,13 +1,11 @@
-#[cfg(feature = "nightly")]
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
 use std::borrow::{Borrow, BorrowMut};
-use std::fmt;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut, RangeBounds};
-use std::slice;
-use std::vec;
+use std::{fmt, slice, vec};
+
+#[cfg(feature = "nightly")]
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 use crate::{Idx, IndexSlice};
 
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index fc7a22833ff..9f6a1763866 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -25,12 +25,11 @@
 //! sometimes useful when the types of `c` and `d` are not traceable
 //! things. (That system should probably be refactored.)
 
-use super::*;
-
-use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation};
 use rustc_middle::bug;
 use rustc_middle::ty::{Const, ImplSubject};
 
+use super::*;
+use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation};
 use crate::traits::Obligation;
 
 /// Whether we should define opaque types or just treat them opaquely.
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 1659f3d0493..3bcb92d8029 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -5,18 +5,19 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::Idx;
+use rustc_middle::bug;
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, BoundVar, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt,
+};
+use smallvec::SmallVec;
+
 use crate::infer::canonical::{
     Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
-use rustc_middle::bug;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_index::Idx;
-use smallvec::SmallVec;
 
 impl<'tcx> InferCtxt<'tcx> {
     /// Canonicalizes a query value `V`. When we canonicalize a query,
diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
index 153de3d4c09..c10df2ec02e 100644
--- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -6,12 +6,12 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable};
-use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, GenericArgKind, TyCtxt};
+
+use crate::infer::canonical::{Canonical, CanonicalVarValues};
 
 /// FIXME(-Znext-solver): This or public because it is shared with the
 /// new trait solver implementation. We should deduplicate canonicalization.
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 8ad4f7926ca..8caedcd4053 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -21,16 +21,15 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::infer::{InferCtxt, RegionVariableOrigin};
+pub use instantiate::CanonicalExt;
 use rustc_index::IndexVec;
+pub use rustc_middle::infer::canonical::*;
 use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, List, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt};
 use rustc_span::Span;
 
-pub use instantiate::CanonicalExt;
-pub use rustc_middle::infer::canonical::*;
+use crate::infer::{InferCtxt, RegionVariableOrigin};
 
 mod canonicalizer;
 mod instantiate;
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index d7dd6a1e7cf..85e3cfbcce1 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -7,6 +7,17 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
+use std::fmt::Debug;
+use std::iter;
+
+use rustc_data_structures::captures::Captures;
+use rustc_index::{Idx, IndexVec};
+use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
+
 use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt};
 use crate::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
@@ -15,19 +26,9 @@ use crate::infer::canonical::{
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult};
 use crate::traits::query::NoSolution;
-use crate::traits::{Obligation, ObligationCause, PredicateObligation};
-use crate::traits::{ScrubbedTraitError, TraitEngine};
-use rustc_data_structures::captures::Captures;
-use rustc_index::Idx;
-use rustc_index::IndexVec;
-use rustc_middle::arena::ArenaAllocatable;
-use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArg, GenericArgKind};
-use rustc_middle::{bug, span_bug};
-use std::fmt::Debug;
-use std::iter;
+use crate::traits::{
+    Obligation, ObligationCause, PredicateObligation, ScrubbedTraitError, TraitEngine,
+};
 
 impl<'tcx> InferCtxt<'tcx> {
     /// This method is meant to be invoked as the final step of a canonical query
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index de4267f7cea..c4294111ebe 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -31,12 +31,14 @@
 //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
 //! inferencer knows "so far".
 
-use super::InferCtxt;
+use std::collections::hash_map::Entry;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt};
-use std::collections::hash_map::Entry;
+
+use super::InferCtxt;
 
 pub struct TypeFreshener<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 72944c9c7de..c2c0c7a41fe 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -1,13 +1,7 @@
 //! Lexical region resolution.
 
-use crate::infer::region_constraints::Constraint;
-use crate::infer::region_constraints::GenericKind;
-use crate::infer::region_constraints::RegionConstraintData;
-use crate::infer::region_constraints::VarInfos;
-use crate::infer::region_constraints::VerifyBound;
-use crate::infer::RegionRelations;
-use crate::infer::RegionVariableOrigin;
-use crate::infer::SubregionOrigin;
+use std::fmt;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
@@ -16,15 +10,18 @@ use rustc_data_structures::intern::Interned;
 use rustc_data_structures::unord::UnordSet;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ReBound, RePlaceholder, ReVar};
-use rustc_middle::ty::{ReEarlyParam, ReErased, ReError, ReLateParam, ReStatic};
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{
+    self, ReBound, ReEarlyParam, ReErased, ReError, ReLateParam, RePlaceholder, ReStatic, ReVar,
+    Region, RegionVid, Ty, TyCtxt,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
-use std::fmt;
 
 use super::outlives::test_type_match;
+use crate::infer::region_constraints::{
+    Constraint, GenericKind, RegionConstraintData, VarInfos, VerifyBound,
+};
+use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin};
 
 /// This function performs lexical region resolution given a complete
 /// set of constraints and variable origins. It performs a fixed-point
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3cee0a622f1..f2fc25a2d2e 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,55 +1,56 @@
-pub use at::DefineOpaqueTypes;
-pub use freshen::TypeFreshener;
-pub use lexical_region_resolve::RegionResolutionError;
-pub use relate::combine::CombineFields;
-pub use relate::combine::PredicateEmittingRelation;
-pub use relate::StructurallyRelateAliases;
-use rustc_errors::DiagCtxtHandle;
-pub use rustc_macros::{TypeFoldable, TypeVisitable};
-pub use rustc_middle::ty::IntVarValue;
-pub use BoundRegionConversionTime::*;
-pub use RegionVariableOrigin::*;
-pub use SubregionOrigin::*;
+use std::cell::{Cell, RefCell};
+use std::fmt;
 
-use crate::infer::relate::RelateResult;
-use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
+pub use at::DefineOpaqueTypes;
 use free_regions::RegionRelations;
+pub use freshen::TypeFreshener;
 use lexical_region_resolve::LexicalRegionResolutions;
+pub use lexical_region_resolve::RegionResolutionError;
 use opaque_types::OpaqueTypeStorage;
-use region_constraints::{GenericKind, VarInfos, VerifyBound};
-use region_constraints::{RegionConstraintCollector, RegionConstraintStorage};
+use region_constraints::{
+    GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound,
+};
+pub use relate::combine::{CombineFields, PredicateEmittingRelation};
+pub use relate::StructurallyRelateAliases;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
 use rustc_data_structures::unify as ut;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::extension;
+pub use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
-use rustc_middle::infer::unify_key::ConstVariableValue;
-use rustc_middle::infer::unify_key::EffectVarValue;
-use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
+use rustc_middle::infer::unify_key::{
+    ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey,
+};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::select;
 use rustc_middle::traits::solve::{Goal, NoSolution};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::BoundVarReplacerDelegate;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{
+    BoundVarReplacerDelegate, TypeFoldable, TypeFolder, TypeSuperFoldable,
+};
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
-use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
-use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
+pub use rustc_middle::ty::IntVarValue;
+use rustc_middle::ty::{
+    self, ConstVid, EffectVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
+    GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use snapshot::undo_log::InferCtxtUndoLogs;
-use std::cell::{Cell, RefCell};
-use std::fmt;
 use type_variable::TypeVariableOrigin;
+pub use BoundRegionConversionTime::*;
+pub use RegionVariableOrigin::*;
+pub use SubregionOrigin::*;
+
+use crate::infer::relate::RelateResult;
+use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
 
 pub mod at;
 pub mod canonical;
@@ -1317,38 +1318,36 @@ impl<'tcx> InferCtxt<'tcx> {
             return inner;
         }
 
-        struct ToFreshVars<'a, 'tcx> {
-            infcx: &'a InferCtxt<'tcx>,
-            span: Span,
-            lbrct: BoundRegionConversionTime,
-            map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
+        let bound_vars = value.bound_vars();
+        let mut args = Vec::with_capacity(bound_vars.len());
+
+        for bound_var_kind in bound_vars {
+            let arg: ty::GenericArg<'_> = match bound_var_kind {
+                ty::BoundVariableKind::Ty(_) => self.next_ty_var(span).into(),
+                ty::BoundVariableKind::Region(br) => {
+                    self.next_region_var(BoundRegion(span, br, lbrct)).into()
+                }
+                ty::BoundVariableKind::Const => self.next_const_var(span).into(),
+            };
+            args.push(arg);
+        }
+
+        struct ToFreshVars<'tcx> {
+            args: Vec<ty::GenericArg<'tcx>>,
         }
 
-        impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'_, 'tcx> {
+        impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'tcx> {
             fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
-                self.map
-                    .entry(br.var)
-                    .or_insert_with(|| {
-                        self.infcx
-                            .next_region_var(BoundRegion(self.span, br.kind, self.lbrct))
-                            .into()
-                    })
-                    .expect_region()
+                self.args[br.var.index()].expect_region()
             }
             fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
-                self.map
-                    .entry(bt.var)
-                    .or_insert_with(|| self.infcx.next_ty_var(self.span).into())
-                    .expect_ty()
+                self.args[bt.var.index()].expect_ty()
             }
             fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
-                self.map
-                    .entry(bv)
-                    .or_insert_with(|| self.infcx.next_const_var(self.span).into())
-                    .expect_const()
+                self.args[bv.index()].expect_const()
             }
         }
-        let delegate = ToFreshVars { infcx: self, span, lbrct, map: Default::default() };
+        let delegate = ToFreshVars { args };
         self.tcx.replace_bound_vars_uncached(value, delegate)
     }
 
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 7c764cccc47..e9726ee8ebf 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -1,6 +1,3 @@
-use crate::errors::OpaqueHiddenTypeDiag;
-use crate::infer::{InferCtxt, InferOk};
-use crate::traits::{self, Obligation};
 use hir::def_id::{DefId, LocalDefId};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::Lrc;
@@ -9,13 +6,16 @@ use rustc_middle::traits::solve::Goal;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::{
-    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, GenericArgKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_span::Span;
 
+use crate::errors::OpaqueHiddenTypeDiag;
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::{self, Obligation};
+
 mod table;
 
 pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index e07d181e4e0..7b4e546d831 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -2,9 +2,8 @@ use rustc_data_structures::undo_log::UndoLogs;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
 
-use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
-
 use super::{OpaqueTypeDecl, OpaqueTypeMap};
+use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
 
 #[derive(Default, Debug, Clone)]
 pub struct OpaqueTypeStorage<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 5bcb4f29364..cc763707c9c 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,12 +1,12 @@
-use crate::infer::free_regions::FreeRegionMap;
-use crate::infer::GenericKind;
-use crate::traits::query::OutlivesBound;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Region};
 
 use super::explicit_outlives_bounds;
+use crate::infer::free_regions::FreeRegionMap;
+use crate::infer::GenericKind;
+use crate::traits::query::OutlivesBound;
 
 /// The `OutlivesEnvironment` collects information about what outlives
 /// what in a given type-checking setting. For example, if we have a
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 89ff4604560..e4eefbc7a1a 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -1,12 +1,13 @@
 //! Various code related to computing outlives relations.
 
+use rustc_middle::traits::query::{NoSolution, OutlivesBound};
+use rustc_middle::ty;
+
 use self::env::OutlivesEnvironment;
 use super::region_constraints::RegionConstraintData;
 use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
 use crate::infer::free_regions::RegionRelations;
 use crate::infer::lexical_region_resolve;
-use rustc_middle::traits::query::{NoSolution, OutlivesBound};
-use rustc_middle::ty;
 
 pub mod env;
 pub mod for_liveness;
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index d82ae7b4fb8..88b004adc94 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -59,25 +59,25 @@
 //! might later infer `?U` to something like `&'b u32`, which would
 //! imply that `'b: 'a`.
 
-use crate::infer::outlives::env::RegionBoundPairs;
-use crate::infer::outlives::verify::VerifyBoundCx;
-use crate::infer::resolve::OpportunisticRegionResolver;
-use crate::infer::snapshot::undo_log::UndoLog;
-use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
-use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_middle::bug;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{
-    self, GenericArgsRef, Region, Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt,
+    self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
+    TypeFoldable as _, TypeVisitableExt,
 };
-use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
 use rustc_span::DUMMY_SP;
 use rustc_type_ir::outlives::{push_outlives_components, Component};
 use smallvec::smallvec;
 
 use super::env::OutlivesEnvironment;
+use crate::infer::outlives::env::RegionBoundPairs;
+use crate::infer::outlives::verify::VerifyBoundCx;
+use crate::infer::resolve::OpportunisticRegionResolver;
+use crate::infer::snapshot::undo_log::UndoLog;
+use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
+use crate::traits::{ObligationCause, ObligationCauseCode};
 
 impl<'tcx> InferCtxt<'tcx> {
     /// Registers that the given region obligation must be resolved
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index c63eeaf812c..835e34a3535 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -2,8 +2,7 @@ use std::collections::hash_map::Entry;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 
 use crate::infer::region_constraints::VerifyIfEq;
 use crate::infer::relate::{self as relate, Relate, RelateResult, TypeRelation};
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 2392a82025a..1908e1e09c3 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,11 +1,13 @@
-use crate::infer::outlives::env::RegionBoundPairs;
-use crate::infer::region_constraints::VerifyIfEq;
-use crate::infer::{GenericKind, VerifyBound};
+use std::assert_matches::assert_matches;
+
 use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
 use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
-
 use smallvec::smallvec;
 
+use crate::infer::outlives::env::RegionBoundPairs;
+use crate::infer::region_constraints::VerifyIfEq;
+use crate::infer::{GenericKind, VerifyBound};
+
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
 /// obligation into a series of `'a: 'b` constraints and "verifys", as
 /// described on the module comment. The final constraints are emitted
@@ -181,7 +183,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         &self,
         generic_ty: Ty<'tcx>,
     ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
-        assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_)));
+        assert_matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_));
         self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
     }
 
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index a1ba43eb171..b78f9d49268 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -1,9 +1,8 @@
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, Ty};
 
-use crate::traits::{Obligation, PredicateObligation};
-
 use super::InferCtxt;
+use crate::traits::{Obligation, PredicateObligation};
 
 impl<'tcx> InferCtxt<'tcx> {
     /// Instead of normalizing an associated type projection,
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 5b159d62731..3d2a0a3356f 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -1,12 +1,14 @@
-use super::*;
-use crate::infer::relate::RelateResult;
-use crate::infer::snapshot::CombinedSnapshot;
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph};
+use rustc_data_structures::graph::scc::Sccs;
+use rustc_data_structures::graph::vec_graph::VecGraph;
 use rustc_index::Idx;
 use rustc_middle::span_bug;
 use rustc_middle::ty::error::TypeError;
 
+use super::*;
+use crate::infer::relate::RelateResult;
+use crate::infer::snapshot::CombinedSnapshot;
+
 impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
     /// Searches new universes created during `snapshot`, looking for
     /// placeholders that may "leak" out from the universes they are contained
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 6f755e07ff1..6ee95c73cfb 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -1,10 +1,7 @@
 //! See `README.md`.
 
-use self::CombineMapType::*;
-use self::UndoLog::*;
-
-use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin};
-use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
+use std::ops::Range;
+use std::{cmp, fmt, mem};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
@@ -13,15 +10,14 @@ use rustc_data_structures::unify as ut;
 use rustc_index::IndexVec;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey};
-use rustc_middle::ty::ReStatic;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ReBound, ReVar};
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 
-use std::ops::Range;
-use std::{cmp, fmt, mem};
+use self::CombineMapType::*;
+use self::UndoLog::*;
+use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin};
+use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
 
 mod leak_check;
 
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 1dc03de4c8b..5751ce466d9 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -18,22 +18,19 @@
 //! On success, the  LUB/GLB operations return the appropriate bound. The
 //! return value of `Equate` or `Sub` shouldn't really be used.
 
+use rustc_middle::bug;
+use rustc_middle::infer::unify_key::EffectVarValue;
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt, UintType, Upcast};
 pub use rustc_next_trait_solver::relate::combine::*;
 
 use super::glb::Glb;
 use super::lub::Lub;
 use super::type_relating::TypeRelating;
-use super::RelateResult;
-use super::StructurallyRelateAliases;
-use crate::infer::relate;
-use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
+use super::{RelateResult, StructurallyRelateAliases};
+use crate::infer::{relate, DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::traits::{Obligation, PredicateObligation};
-use rustc_middle::bug;
-use rustc_middle::infer::unify_key::EffectVarValue;
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
-use rustc_middle::ty::{IntType, UintType};
 
 #[derive(Clone)]
 pub struct CombineFields<'infcx, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 30cfbcae6b2..542104fa10b 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -1,10 +1,5 @@
 use std::mem;
 
-use super::StructurallyRelateAliases;
-use super::{PredicateEmittingRelation, Relate, RelateResult, TypeRelation};
-use crate::infer::relate;
-use crate::infer::type_variable::TypeVariableValue;
-use crate::infer::{InferCtxt, RegionVariableOrigin};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
@@ -12,10 +7,17 @@ use rustc_middle::bug;
 use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::visit::MaxUniverse;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
+};
 use rustc_span::Span;
 
+use super::{
+    PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
+};
+use crate::infer::type_variable::TypeVariableValue;
+use crate::infer::{relate, InferCtxt, RegionVariableOrigin};
+
 impl<'tcx> InferCtxt<'tcx> {
     /// The idea is that we should ensure that the type variable `target_vid`
     /// is equal to, a subtype of, or a supertype of `source_ty`.
diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
index cfce28aca5d..c808ab5e6dd 100644
--- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
+++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
@@ -1,11 +1,12 @@
 //! Helper routines for higher-ranked things. See the `doc` module at
 //! the end of the file for details.
 
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+
 use super::RelateResult;
 use crate::infer::snapshot::CombinedSnapshot;
 use crate::infer::InferCtxt;
-use rustc_middle::ty::fold::FnMutDelegate;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 impl<'tcx> InferCtxt<'tcx> {
     /// Replaces all bound variables (lifetimes, types, and constants) bound by
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index d1d87071562..f555fedbb5b 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -17,14 +17,13 @@
 //!
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
+use rustc_middle::ty::relate::RelateResult;
+use rustc_middle::ty::{self, Ty, TyVar};
+
 use super::combine::PredicateEmittingRelation;
 use crate::infer::{DefineOpaqueTypes, InferCtxt};
 use crate::traits::ObligationCause;
 
-use rustc_middle::ty::relate::RelateResult;
-use rustc_middle::ty::TyVar;
-use rustc_middle::ty::{self, Ty};
-
 /// Trait for returning data about a lattice, and for abstracting
 /// over the "direction" of the lattice operation (LUB/GLB).
 ///
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 2eb20f311cf..046e93b63e4 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -1,16 +1,16 @@
 //! Least upper bound. See [`lattice`].
 
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::Span;
+
 use super::combine::{CombineFields, PredicateEmittingRelation};
 use super::lattice::{self, LatticeDir};
 use super::StructurallyRelateAliases;
 use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
 use crate::traits::ObligationCause;
 
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
-
 /// "Least upper bound" (common supertype)
 pub struct Lub<'combine, 'infcx, 'tcx> {
     fields: &'combine mut CombineFields<'infcx, 'tcx>,
diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs
index dd97dc061fe..183ea5b3309 100644
--- a/compiler/rustc_infer/src/infer/relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/relate/mod.rs
@@ -5,8 +5,7 @@
 pub use rustc_middle::ty::relate::RelateResult;
 pub use rustc_next_trait_solver::relate::*;
 
-pub use self::combine::CombineFields;
-pub use self::combine::PredicateEmittingRelation;
+pub use self::combine::{CombineFields, PredicateEmittingRelation};
 
 #[allow(hidden_glob_reexports)]
 pub(super) mod combine;
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 3fe35354286..ec600c60b24 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -1,15 +1,15 @@
-use super::combine::CombineFields;
-use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
-use crate::infer::BoundRegionConversionTime::HigherRankedType;
-use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::relate::{
     relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation,
 };
-use rustc_middle::ty::TyVar;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TyVar};
 use rustc_span::Span;
 
+use super::combine::CombineFields;
+use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
+use crate::infer::BoundRegionConversionTime::HigherRankedType;
+use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
+
 /// Enforce that `a` is equal to or a subtype of `b`.
 pub struct TypeRelating<'combine, 'a, 'tcx> {
     fields: &'combine mut CombineFields<'a, 'tcx>,
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index ed75fd183f2..34625ffb778 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,9 +1,10 @@
-use super::{FixupError, FixupResult, InferCtxt};
 use rustc_middle::bug;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
 
+use super::{FixupError, FixupResult, InferCtxt};
+
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC VAR RESOLVER
 
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index f15bd0babee..bc954054ea2 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -1,16 +1,13 @@
+use std::ops::Range;
+
+use rustc_data_structures::{snapshot_vec as sv, unify as ut};
 use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
-
-use crate::infer::type_variable::TypeVariableOrigin;
-use crate::infer::InferCtxt;
-use crate::infer::{ConstVariableOrigin, RegionVariableOrigin, UnificationTable};
-
-use rustc_data_structures::snapshot_vec as sv;
-use rustc_data_structures::unify as ut;
 use ut::UnifyKey;
 
-use std::ops::Range;
+use crate::infer::type_variable::TypeVariableOrigin;
+use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable};
 
 fn vars_since_snapshot<'tcx, T>(
     table: &UnificationTable<'_, 'tcx, T>,
diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs
index 9eef1471b1a..d76b9b00001 100644
--- a/compiler/rustc_infer/src/infer/snapshot/mod.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs
@@ -1,8 +1,9 @@
-use super::region_constraints::RegionSnapshot;
-use super::InferCtxt;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_middle::ty;
 
+use super::region_constraints::RegionSnapshot;
+use super::InferCtxt;
+
 mod fudge;
 pub(crate) mod undo_log;
 
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index 829b0a73a0d..50a0d3bf214 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -1,15 +1,12 @@
 use std::marker::PhantomData;
 
-use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
-use rustc_data_structures::unify as ut;
+use rustc_data_structures::{snapshot_vec as sv, unify as ut};
 use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
 
-use crate::{
-    infer::{region_constraints, type_variable, InferCtxtInner},
-    traits,
-};
+use crate::infer::{region_constraints, type_variable, InferCtxtInner};
+use crate::traits;
 
 pub struct Snapshot<'tcx> {
     pub(crate) undo_len: usize,
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index b56b39e61f0..f022b8ab637 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -1,4 +1,9 @@
+use std::cmp;
+use std::marker::PhantomData;
+use std::ops::Range;
+
 use rustc_data_structures::undo_log::Rollback;
+use rustc_data_structures::{snapshot_vec as sv, unify as ut};
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
 use rustc_middle::bug;
@@ -7,12 +12,6 @@ use rustc_span::Span;
 
 use crate::infer::InferCtxtUndoLogs;
 
-use rustc_data_structures::snapshot_vec as sv;
-use rustc_data_structures::unify as ut;
-use std::cmp;
-use std::marker::PhantomData;
-use std::ops::Range;
-
 impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> {
     fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
         self.eq_relations.reverse(undo)
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index b65ac859667..25ac8ba974b 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -18,6 +18,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 026b2c1b905..fd38040406d 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,11 +1,11 @@
 use std::fmt::Debug;
 
-use crate::infer::InferCtxt;
-use crate::traits::Obligation;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Ty, Upcast};
 
 use super::{ObligationCause, PredicateObligation};
+use crate::infer::InferCtxt;
+use crate::traits::Obligation;
 
 /// A trait error with most of its information removed. This is the error
 /// returned by an `ObligationCtxt` by default, and suitable if you just
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 7bc3af374fc..4f34c139545 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -14,21 +14,19 @@ use hir::def_id::LocalDefId;
 use rustc_hir as hir;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
+pub use rustc_middle::traits::*;
 use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
 
-pub use self::ImplSource::*;
-pub use self::SelectionError::*;
-use crate::infer::InferCtxt;
-
 pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine};
-pub use self::project::MismatchedProjectionTypes;
 pub(crate) use self::project::UndoLog;
 pub use self::project::{
-    Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
-    ProjectionCacheStorage, Reveal,
+    MismatchedProjectionTypes, Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry,
+    ProjectionCacheKey, ProjectionCacheStorage, Reveal,
 };
-pub use rustc_middle::traits::*;
+pub use self::ImplSource::*;
+pub use self::SelectionError::*;
+use crate::infer::InferCtxt;
 
 /// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
 /// which the "impl_source" must be found. The process of finding an "impl_source" is
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index b696264aab0..9ed557ec40b 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -1,16 +1,12 @@
 //! Code for projecting associated types out of trait references.
 
-use super::PredicateObligation;
-
-use crate::infer::snapshot::undo_log::InferCtxtUndoLogs;
-
-use rustc_data_structures::{
-    snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage},
-    undo_log::Rollback,
-};
+use rustc_data_structures::snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage};
+use rustc_data_structures::undo_log::Rollback;
+pub use rustc_middle::traits::{EvaluationResult, Reveal};
 use rustc_middle::ty;
 
-pub use rustc_middle::traits::{EvaluationResult, Reveal};
+use super::PredicateObligation;
+use crate::infer::snapshot::undo_log::InferCtxtUndoLogs;
 
 pub(crate) type UndoLog<'tcx> =
     snapshot_map::UndoLog<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>;
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index b26734a296f..31f585c0c9e 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -1,11 +1,12 @@
-use crate::traits;
-use crate::traits::project::Normalized;
+use std::fmt;
+
 use rustc_ast_ir::try_visit;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor};
 use rustc_middle::ty::{self, TyCtxt};
 
-use std::fmt;
+use crate::traits;
+use crate::traits::project::Normalized;
 
 // Structural impls for the structs in `traits`.
 
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f54d0418595..335c65da054 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,11 +1,11 @@
-use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::ToPolyTraitRef;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 pub use rustc_type_ir::elaborate::*;
 
+use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
+
 pub fn anonymize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
     pred: ty::Predicate<'tcx>,
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index a27f73789cd..786e2bb511f 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -9,12 +9,13 @@
 //! The functions in this file should fall back to the default set in their
 //! origin crate when the `TyCtxt` is not present in TLS.
 
+use std::fmt;
+
 use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC};
 use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
 use rustc_middle::ty::tls;
 use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
 use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode};
-use std::fmt;
 
 fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
     tls::with_opt(|tcx| {
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 29294003b8f..939980a932f 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -1,9 +1,9 @@
-use rustc_macros::Diagnostic;
-use rustc_span::{Span, Symbol};
-
 use std::io;
 use std::path::Path;
 
+use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
+
 #[derive(Diagnostic)]
 #[diag(interface_ferris_identifier)]
 pub struct FerrisIdentifier {
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index dba20e4a335..04e2b7d45dc 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -1,13 +1,13 @@
-use crate::util;
+use std::path::PathBuf;
+use std::result;
+use std::sync::Arc;
 
-use rustc_ast::token;
-use rustc_ast::{LitKind, MetaItemKind};
+use rustc_ast::{token, LitKind, MetaItemKind};
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::defer;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::jobserver;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::{defer, jobserver};
 use rustc_errors::registry::Registry;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
 use rustc_lint::LintStore;
@@ -15,6 +15,7 @@ use rustc_middle::ty;
 use rustc_middle::ty::CurrentGcx;
 use rustc_middle::util::Providers;
 use rustc_parse::new_parser_from_source_str;
+use rustc_parse::parser::attr::AllowLeadingUnsafe;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
 use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
@@ -24,11 +25,10 @@ use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs};
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
-use std::path::PathBuf;
-use std::result;
-use std::sync::Arc;
 use tracing::trace;
 
+use crate::util;
+
 pub type Result<T> = result::Result<T, ErrorGuaranteed>;
 
 /// Represents a compiler session. Note that every `Compiler` contains a
@@ -68,7 +68,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
             }
 
             match new_parser_from_source_str(&psess, filename, s.to_string()) {
-                Ok(mut parser) => match parser.parse_meta_item() {
+                Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if meta_item.path.segments.len() != 1 {
                             error!("argument key must be an identifier");
@@ -174,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
             }
         };
 
-        let meta_item = match parser.parse_meta_item() {
+        let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) {
             Ok(meta_item) if parser.token == token::Eof => meta_item,
             Ok(..) => expected_error(),
             Err(err) => {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 2951f50b1f5..96a6f52d60b 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1,7 +1,9 @@
-use crate::errors;
-use crate::interface::{Compiler, Result};
-use crate::proc_macro_decls;
-use crate::util;
+use std::any::Any;
+use std::ffi::OsString;
+use std::io::{self, BufWriter, Write};
+use std::path::{Path, PathBuf};
+use std::sync::{Arc, LazyLock};
+use std::{env, fs, iter};
 
 use rustc_ast::{self as ast, visit};
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -27,23 +29,18 @@ use rustc_resolve::Resolver;
 use rustc_session::code_stats::VTableSizeInfo;
 use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use rustc_session::cstore::Untracked;
-use rustc_session::output::filename_for_input;
-use rustc_session::output::{collect_crate_types, find_crate_name};
+use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::FileName;
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
-
-use std::any::Any;
-use std::ffi::OsString;
-use std::io::{self, BufWriter, Write};
-use std::path::{Path, PathBuf};
-use std::sync::{Arc, LazyLock};
-use std::{env, fs, iter};
 use tracing::{info, instrument};
 
+use crate::interface::{Compiler, Result};
+use crate::{errors, proc_macro_decls, util};
+
 pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
     let krate = sess
         .time("parse_crate", || {
@@ -547,7 +544,13 @@ fn resolver_for_lowering_raw<'tcx>(
     let arenas = Resolver::arenas();
     let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`.
     let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal();
-    let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas);
+    let mut resolver = Resolver::new(
+        tcx,
+        &pre_configured_attrs,
+        krate.spans.inner_span,
+        krate.spans.inject_use_span,
+        &arenas,
+    );
     let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
 
     // Make sure we don't mutate the cstore from here on.
@@ -815,6 +818,19 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     });
     sess.time("layout_testing", || layout_test::test_layout(tcx));
     sess.time("abi_testing", || abi_test::test_abi(tcx));
+
+    // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
+    // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
+    // in MIR optimizations that may only be reachable through codegen, or other codepaths
+    // that requires the optimized/ctfe MIR, such as polymorphization, coroutine bodies,
+    // or evaluating consts.
+    if tcx.sess.opts.unstable_opts.validate_mir {
+        sess.time("ensuring_final_MIR_is_computable", || {
+            tcx.hir().par_body_owners(|def_id| {
+                tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
+            });
+        });
+    }
 }
 
 /// Runs the type-checking, region checking and other miscellaneous analysis
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 821e8ee7ba5..c5d56c15c6e 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -1,6 +1,6 @@
-use crate::errors::FailedWritingFile;
-use crate::interface::{Compiler, Result};
-use crate::{errors, passes};
+use std::any::Any;
+use std::cell::{RefCell, RefMut};
+use std::sync::Arc;
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -15,9 +15,10 @@ use rustc_middle::ty::{GlobalCtxt, TyCtxt};
 use rustc_serialize::opaque::FileEncodeResult;
 use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::Session;
-use std::any::Any;
-use std::cell::{RefCell, RefMut};
-use std::sync::Arc;
+
+use crate::errors::FailedWritingFile;
+use crate::interface::{Compiler, Result};
+use crate::{errors, passes};
 
 /// Represent the result of a query.
 ///
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 7d7a6a08bee..34f2dca7c42 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -1,23 +1,20 @@
 #![allow(rustc::bad_opt_access)]
-use crate::interface::{initialize_checked_jobserver, parse_cfg};
+use std::collections::{BTreeMap, BTreeSet};
+use std::num::NonZero;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+
 use rustc_data_structures::profiling::TimePassesFormat;
-use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
-use rustc_session::config::{build_configuration, build_session_options, rustc_optgroups};
-use rustc_session::config::{
-    BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions,
-    DebugInfo, DumpMonoStatsFormat, ErrorOutputType,
-};
-use rustc_session::config::{
-    ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input,
-    InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto,
-};
-use rustc_session::config::{
-    LocationDetail, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType,
-    OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry,
-};
+use rustc_errors::emitter::HumanReadableErrorType;
+use rustc_errors::{registry, ColorConfig};
 use rustc_session::config::{
-    Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion,
-    WasiExecModel,
+    build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
+    CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat,
+    ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold,
+    Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail,
+    LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey,
+    PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip,
+    SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
 };
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
@@ -31,10 +28,8 @@ use rustc_target::spec::{
     CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
     RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi,
 };
-use std::collections::{BTreeMap, BTreeSet};
-use std::num::NonZero;
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
+
+use crate::interface::{initialize_checked_jobserver, parse_cfg};
 
 fn sess_and_cfg<F>(args: &[&'static str], f: F)
 where
@@ -320,7 +315,8 @@ fn test_search_paths_tracking_hash_different_order() {
     let early_dcx = EarlyDiagCtxt::new(JSON);
     const JSON: ErrorOutputType = ErrorOutputType::Json {
         pretty: false,
-        json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
+        json_rendered: HumanReadableErrorType::Default,
+        color_config: ColorConfig::Never,
     };
 
     let push = |opts: &mut Options, search_path| {
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 8dac524bb5b..761d288a7c2 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -1,4 +1,9 @@
-use crate::errors;
+use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
+use std::path::{Path, PathBuf};
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::OnceLock;
+use std::{env, iter, thread};
+
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
 #[cfg(parallel_compiler)]
@@ -16,14 +21,10 @@ use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMapInputs;
 use rustc_span::symbol::sym;
 use rustc_target::spec::Target;
-use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
-use std::path::{Path, PathBuf};
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::OnceLock;
-use std::thread;
-use std::{env, iter};
 use tracing::info;
 
+use crate::errors;
+
 /// Function pointer type that constructs a new CodegenBackend.
 pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
 
@@ -136,11 +137,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
     sm_inputs: SourceMapInputs,
     f: F,
 ) -> R {
-    use rustc_data_structures::{defer, jobserver, sync::FromDyn};
+    use std::process;
+
+    use rustc_data_structures::sync::FromDyn;
+    use rustc_data_structures::{defer, jobserver};
     use rustc_middle::ty::tls;
     use rustc_query_impl::QueryCtxt;
     use rustc_query_system::query::{break_query_cycles, QueryContext};
-    use std::process;
 
     let thread_stack_size = init_stack_size(thread_builder_diag);
 
@@ -383,7 +386,6 @@ fn get_codegen_sysroot(
     }
 }
 
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub(crate) fn check_attr_crate_type(
     sess: &Session,
     attrs: &[ast::Attribute],
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index d4efb41eed0..2116ba6c079 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -31,12 +31,12 @@ pub mod unescape;
 #[cfg(test)]
 mod tests;
 
-pub use crate::cursor::Cursor;
+use unicode_properties::UnicodeEmoji;
 
 use self::LiteralKind::*;
 use self::TokenKind::*;
+pub use crate::cursor::Cursor;
 use crate::cursor::EOF_CHAR;
-use unicode_properties::UnicodeEmoji;
 
 /// Parsed token.
 /// It doesn't contain information about data that has been parsed,
diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs
index e4c1787f2cc..493ec2b0f60 100644
--- a/compiler/rustc_lexer/src/tests.rs
+++ b/compiler/rustc_lexer/src/tests.rs
@@ -1,7 +1,7 @@
-use super::*;
-
 use expect_test::{expect, Expect};
 
+use super::*;
+
 fn check_raw_str(s: &str, expected: Result<u8, RawStrError>) {
     let s = &format!("r{}", s);
     let mut cursor = Cursor::new(s);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 987dbf6db63..7a394a6d6c1 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -518,8 +518,8 @@ lint_non_binding_let_multi_suggestion =
 lint_non_binding_let_on_drop_type =
     non-binding let on a type that implements `Drop`
 
-lint_non_binding_let_on_sync_lock =
-    non-binding let on a synchronization lock
+lint_non_binding_let_on_sync_lock = non-binding let on a synchronization lock
+    .label = this lock is not assigned to a binding and is immediately dropped
 
 lint_non_binding_let_suggestion =
     consider binding to an unused variable to avoid immediately dropping the value
@@ -700,10 +700,10 @@ lint_reason_must_be_string_literal = reason must be a string literal
 lint_reason_must_come_last = reason in lint attribute must come last
 
 lint_redundant_import = the item `{$ident}` is imported redundantly
-    .label_imported_here = the item `{ident}` is already imported here
-    .label_defined_here = the item `{ident}` is already defined here
-    .label_imported_prelude = the item `{ident}` is already imported by the extern prelude
-    .label_defined_prelude = the item `{ident}` is already defined by the extern prelude
+    .label_imported_here = the item `{$ident}` is already imported here
+    .label_defined_here = the item `{$ident}` is already defined here
+    .label_imported_prelude = the item `{$ident}` is already imported by the extern prelude
+    .label_defined_prelude = the item `{$ident}` is already defined by the extern prelude
 
 lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough
     .note = the most public imported item is `{$max_vis}`
@@ -775,6 +775,10 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
     .label = argument has type `{$arg_ty}`
     .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
 
+lint_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag
+    .controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`
+    .incoherent = manually setting a built-in cfg can and does create incoherent behaviors
+
 lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
 lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
 lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs
index 6daee95dda6..d9040207300 100644
--- a/compiler/rustc_lint/src/async_fn_in_trait.rs
+++ b/compiler/rustc_lint/src/async_fn_in_trait.rs
@@ -1,10 +1,10 @@
-use crate::lints::AsyncFnInTraitDiag;
-use crate::LateContext;
-use crate::LateLintPass;
 use rustc_hir as hir;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_trait_selection::error_reporting::traits::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait;
 
+use crate::lints::AsyncFnInTraitDiag;
+use crate::{LateContext, LateLintPass};
+
 declare_lint! {
     /// The `async_fn_in_trait` lint detects use of `async fn` in the
     /// definition of a publicly-reachable trait.
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ab0b47d48e5..6b36944b208 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -20,25 +20,8 @@
 //! If you define a new `LateLintPass`, you will also need to add it to the
 //! `late_lint_methods!` invocation in `lib.rs`.
 
-use crate::fluent_generated as fluent;
-use crate::{
-    errors::BuiltinEllipsisInclusiveRangePatterns,
-    lints::{
-        BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
-        BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
-        BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
-        BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
-        BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
-        BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
-        BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
-        BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
-        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
-        BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
-        BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
-        BuiltinWhileTrue, InvalidAsmLabel,
-    },
-    EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
-};
+use std::fmt::Write;
+
 use ast::token::TokenKind;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
@@ -55,9 +38,9 @@ use rustc_middle::bug;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::Upcast;
-use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
+// hardwired lints from rustc_lint_defs
+pub use rustc_session::lint::builtin::*;
 use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::edition::Edition;
@@ -67,15 +50,29 @@ use rustc_span::{BytePos, InnerSpan, Span};
 use rustc_target::abi::Abi;
 use rustc_target::asm::InlineAsmArch;
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
+use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
-
+use rustc_trait_selection::traits::{self};
+
+use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
+use crate::lints::{
+    BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
+    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
+    BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
+    BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
+    BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
+    BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes,
+    BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed,
+    BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
+    BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
+    BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
+    BuiltinWhileTrue, InvalidAsmLabel,
+};
 use crate::nonstandard_style::{method_context, MethodLateContext};
-
-use std::fmt::Write;
-
-// hardwired lints from rustc_lint_defs
-pub use rustc_session::lint::builtin::*;
+use crate::{
+    fluent_generated as fluent, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level,
+    LintContext,
+};
 
 declare_lint! {
     /// The `while_true` lint detects `while true { }`.
@@ -1672,7 +1669,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
             return;
         }
 
-        use self::ast::{PatKind, RangeSyntax::DotDotDot};
+        use self::ast::PatKind;
+        use self::ast::RangeSyntax::DotDotDot;
 
         /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
         /// corresponding to the ellipsis.
@@ -1926,14 +1924,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
         tcx: TyCtxt<'tcx>,
-        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
+        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
         item: DefId,
         lifetime: DefId,
     ) -> Vec<ty::Region<'tcx>> {
         let item_generics = tcx.generics_of(item);
 
         inferred_outlives
-            .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
                     ty::ReEarlyParam(ebr)
@@ -1949,11 +1946,10 @@ impl ExplicitOutlivesRequirements {
     }
 
     fn lifetimes_outliving_type<'tcx>(
-        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
+        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
         index: u32,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
-            .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
                     a.is_param(index).then_some(b)
@@ -2096,7 +2092,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                 (
                                     Self::lifetimes_outliving_lifetime(
                                         cx.tcx,
-                                        inferred_outlives,
+                                        // don't warn if the inferred span actually came from the predicate we're looking at
+                                        // this happens if the type is recursively defined
+                                        inferred_outlives
+                                            .iter()
+                                            .filter(|(_, span)| !predicate.span.contains(*span)),
                                         item.owner_id.to_def_id(),
                                         region_def_id,
                                     ),
@@ -2118,7 +2118,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                     };
                                     let index = ty_generics.param_def_id_to_index[&def_id];
                                     (
-                                        Self::lifetimes_outliving_type(inferred_outlives, index),
+                                        Self::lifetimes_outliving_type(
+                                            // don't warn if the inferred span actually came from the predicate we're looking at
+                                            // this happens if the type is recursively defined
+                                            inferred_outlives.iter().filter(|(_, span)| {
+                                                !predicate.span.contains(*span)
+                                            }),
+                                            index,
+                                        ),
                                         &predicate.bounds,
                                         predicate.span,
                                         predicate.origin == PredicateOrigin::WhereClause,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 9f0f116cbd0..c9e2eee16b3 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -14,10 +14,9 @@
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use self::TargetLint::*;
+use std::cell::Cell;
+use std::{iter, slice};
 
-use crate::levels::LintLevelsBuilder;
-use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync;
 use rustc_data_structures::unord::UnordMap;
@@ -30,20 +29,22 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::bug;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError, PrintTraitRefExt as _};
-use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt};
-use rustc_session::lint::{BuiltinLintDiag, LintExpectationId};
-use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
+use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError, PrintTraitRefExt as _, Printer};
+use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_session::lint::{
+    BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId,
+};
 use rustc_session::{LintStoreMarker, Session};
 use rustc_span::edit_distance::find_best_match_for_names;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi;
-use std::cell::Cell;
-use std::iter;
-use std::slice;
 use tracing::debug;
 
+use self::TargetLint::*;
+use crate::levels::LintLevelsBuilder;
+use crate::passes::{EarlyLintPassObject, LateLintPassObject};
+
 mod diagnostics;
 
 type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
@@ -532,7 +533,7 @@ pub struct EarlyContext<'a> {
 }
 
 impl EarlyContext<'_> {
-    /// Emit a lint at the appropriate level, with an optional associated span and an existing
+    /// Emit a lint at the appropriate level, with an associated span and an existing
     /// diagnostic.
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
@@ -543,7 +544,21 @@ impl EarlyContext<'_> {
         span: MultiSpan,
         diagnostic: BuiltinLintDiag,
     ) {
-        self.opt_span_lint(lint, Some(span), |diag| {
+        self.opt_span_lint_with_diagnostics(lint, Some(span), diagnostic);
+    }
+
+    /// Emit a lint at the appropriate level, with an optional associated span and an existing
+    /// diagnostic.
+    ///
+    /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
+    pub fn opt_span_lint_with_diagnostics(
+        &self,
+        lint: &'static Lint,
+        span: Option<MultiSpan>,
+        diagnostic: BuiltinLintDiag,
+    ) {
+        self.opt_span_lint(lint, span, |diag| {
             diagnostics::decorate_lint(self.sess(), diagnostic, diag);
         });
     }
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 05e075205c4..f289d4c81b3 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -4,8 +4,9 @@
 use std::borrow::Cow;
 
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
-use rustc_errors::elided_lifetime_in_path_suggestion;
-use rustc_errors::{Applicability, Diag, DiagArgValue, LintDiagnostic};
+use rustc_errors::{
+    elided_lifetime_in_path_suggestion, Applicability, Diag, DiagArgValue, LintDiagnostic,
+};
 use rustc_middle::middle::stability;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::Session;
@@ -437,5 +438,8 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
         BuiltinLintDiag::OutOfScopeMacroCalls { path } => {
             lints::OutOfScopeMacroCalls { path }.decorate_lint(diag)
         }
+        BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
+            lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
+        }
     }
 }
diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
index da36f68fca9..fb3f40aa271 100644
--- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
@@ -1,5 +1,6 @@
 use rustc_middle::bug;
-use rustc_session::{config::ExpectedValues, Session};
+use rustc_session::config::ExpectedValues;
+use rustc_session::Session;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{sym, Span, Symbol};
 
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 911975f6179..f174470b7a7 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -1,8 +1,3 @@
-use crate::{
-    lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel},
-    LateContext, LateLintPass, LintContext,
-};
-
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::ty;
 use rustc_session::lint::FutureIncompatibilityReason;
@@ -10,6 +5,9 @@ use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::sym;
 use rustc_trait_selection::traits::supertraits;
 
+use crate::lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel};
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
     /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs
index eea0898d83f..2060858cc8a 100644
--- a/compiler/rustc_lint/src/drop_forget_useless.rs
+++ b/compiler/rustc_lint/src/drop_forget_useless.rs
@@ -3,13 +3,11 @@ use rustc_middle::ty;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::sym;
 
-use crate::{
-    lints::{
-        DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag,
-        UndroppedManuallyDropsSuggestion, UseLetUnderscoreIgnoreSuggestion,
-    },
-    LateContext, LateLintPass, LintContext,
+use crate::lints::{
+    DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag,
+    UndroppedManuallyDropsSuggestion, UseLetUnderscoreIgnoreSuggestion,
 };
+use crate::{LateContext, LateLintPass, LintContext};
 
 declare_lint! {
     /// The `dropping_references` lint checks for calls to `std::mem::drop` with a reference
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 329221612b5..6fb0a624644 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -14,8 +14,6 @@
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use crate::context::{EarlyContext, LintStore};
-use crate::passes::{EarlyLintPass, EarlyLintPassObject};
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self as ast_visit, walk_list, Visitor};
 use rustc_ast::{self as ast, HasAttrs};
@@ -28,6 +26,9 @@ use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use tracing::debug;
 
+use crate::context::{EarlyContext, LintStore};
+use crate::passes::{EarlyLintPass, EarlyLintPassObject};
+
 macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
@@ -46,7 +47,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
     fn inlined_check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.context.buffered.take(id) {
             let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
-            self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
+            self.context.opt_span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
         }
     }
 
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index 958da177eda..4e3eca496ea 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -1,12 +1,13 @@
-use crate::{
-    context::LintContext,
-    lints::{EnumIntrinsicsMemDiscriminate, EnumIntrinsicsMemVariant},
-    LateContext, LateLintPass,
-};
 use rustc_hir as hir;
-use rustc_middle::ty::{visit::TypeVisitableExt, Ty};
+use rustc_middle::ty::visit::TypeVisitableExt;
+use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+use crate::context::LintContext;
+use crate::lints::{EnumIntrinsicsMemDiscriminate, EnumIntrinsicsMemVariant};
+use crate::{LateContext, LateLintPass};
 
 declare_lint! {
     /// The `enum_intrinsics_non_enums` lint detects calls to
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 46dfaf0b83f..23e6b73ee37 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,9 +1,11 @@
-use crate::fluent_generated as fluent;
-use rustc_errors::{codes::*, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::lint::Level;
 use rustc_span::{Span, Symbol};
 
+use crate::fluent_generated as fluent;
+
 #[derive(Diagnostic)]
 #[diag(lint_overruled_attribute, code = E0453)]
 pub struct OverruledAttribute<'a> {
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 04c2ebf189f..35af694213d 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,10 +1,11 @@
-use crate::lints::{Expectation, ExpectationNote};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
 use rustc_session::lint::LintExpectationId;
 use rustc_span::Symbol;
 
+use crate::lints::{Expectation, ExpectationNote};
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_expectations, ..*providers };
 }
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index aa00fb4573d..6cb5263ac54 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -1,19 +1,18 @@
-use crate::{
-    lints::{
-        ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark,
-        ForLoopsOverFalliblesSuggestion,
-    },
-    LateContext, LateLintPass, LintContext,
-};
-
 use hir::{Expr, Pat};
 use rustc_hir as hir;
-use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::ObligationCtxt;
 
+use crate::lints::{
+    ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark,
+    ForLoopsOverFalliblesSuggestion,
+};
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
     ///
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index aa8ca1776dc..ebd8bd5605d 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -1,15 +1,13 @@
-use crate::{
-    lints::{
-        HiddenUnicodeCodepointsDiag, HiddenUnicodeCodepointsDiagLabels,
-        HiddenUnicodeCodepointsDiagSub,
-    },
-    EarlyContext, EarlyLintPass, LintContext,
-};
 use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
 use rustc_ast as ast;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{BytePos, Span, Symbol};
 
+use crate::lints::{
+    HiddenUnicodeCodepointsDiag, HiddenUnicodeCodepointsDiagLabels, HiddenUnicodeCodepointsDiagSub,
+};
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+
 declare_lint! {
     /// The `text_direction_codepoint_in_literal` lint detects Unicode codepoints that change the
     /// visual representation of text on screen in a way that does not correspond to their on
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 0860413190c..e914169f4c3 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -13,8 +13,7 @@ use rustc_middle::ty::{
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::Span;
 
-use crate::fluent_generated as fluent;
-use crate::{LateContext, LateLintPass};
+use crate::{fluent_generated as fluent, LateContext, LateLintPass};
 
 declare_lint! {
     /// The `impl_trait_overcaptures` lint warns against cases where lifetime
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index e15eb90f827..044c9413f0b 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -1,16 +1,13 @@
 //! Some lints that are only useful in the compiler or crates that use compiler internals, such as
 //! Clippy.
 
-use crate::lints::{
-    BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
-    NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag,
-    TykindKind, UntranslatableDiag,
-};
-use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_hir::def::Res;
-use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
-use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{
+    BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind,
+    Path, PathSegment, QPath, Ty, TyKind,
+};
 use rustc_middle::ty::{self, Ty as MiddleTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -18,6 +15,13 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 use tracing::debug;
 
+use crate::lints::{
+    BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
+    NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag,
+    TykindKind, UntranslatableDiag,
+};
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+
 declare_tool_lint! {
     /// The `default_hash_type` lint detects use of [`std::collections::HashMap`] and
     /// [`std::collections::HashSet`], suggesting the use of `FxHashMap`/`FxHashSet`.
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index aa328fb87b2..638b623510e 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -14,22 +14,24 @@
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
+use std::any::Any;
+use std::cell::Cell;
+
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::{join, Lrc};
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
-use rustc_hir::intravisit as hir_visit;
-use rustc_hir::HirId;
+use rustc_hir::{intravisit as hir_visit, HirId};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::LintPass;
 use rustc_session::Session;
 use rustc_span::Span;
-use std::any::Any;
-use std::cell::Cell;
 use tracing::debug;
 
+use crate::passes::LateLintPassObject;
+use crate::{LateContext, LateLintPass, LintStore};
+
 /// Extract the [`LintStore`] from [`Session`].
 ///
 /// This function exists because [`Session::lint_store`] is type-erased.
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index e6c274ec09a..1368cc87e3e 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -1,13 +1,12 @@
-use crate::{
-    lints::{NonBindingLet, NonBindingLetSub},
-    LateContext, LateLintPass, LintContext,
-};
 use rustc_errors::MultiSpan;
 use rustc_hir as hir;
 use rustc_middle::ty;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{sym, Symbol};
 
+use crate::lints::{NonBindingLet, NonBindingLetSub};
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `let_underscore_drop` lint checks for statements which don't bind
     /// an expression which has a non-trivial Drop implementation to anything,
@@ -105,7 +104,6 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
         if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
             return;
@@ -157,12 +155,12 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                 is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)),
             };
             if is_sync_lock {
-                let mut span = MultiSpan::from_span(pat.span);
-                span.push_span_label(
-                    pat.span,
-                    "this lock is not assigned to a binding and is immediately dropped".to_string(),
+                let span = MultiSpan::from_span(pat.span);
+                cx.emit_span_lint(
+                    LET_UNDERSCORE_LOCK,
+                    span,
+                    NonBindingLet::SyncLock { sub, pat: pat.span },
                 );
-                cx.emit_span_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub });
             // Only emit let_underscore_drop for top-level `_` patterns.
             } else if can_use_init.is_some() {
                 cx.emit_span_lint(LET_UNDERSCORE_DROP, local.span, NonBindingLet::DropType { sub });
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 0df34c32e38..44117e5d7a5 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,24 +1,7 @@
-use crate::errors::{CheckNameUnknownTool, RequestedLevel, UnsupportedGroup};
-use crate::lints::{
-    DeprecatedLintNameFromCommandLine, RemovedLintFromCommandLine, RenamedLintFromCommandLine,
-    UnknownLintFromCommandLine,
-};
-use crate::{
-    builtin::MISSING_DOCS,
-    context::{CheckLintNameResult, LintStore},
-    fluent_generated as fluent,
-    late::unerased_lint_store,
-    lints::{
-        DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAttributeLint, RemovedLint,
-        RenamedLint, RenamedLintSuggestion, UnknownLint, UnknownLintSuggestion,
-    },
-};
-use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
 use rustc_feature::{Features, GateIssue};
-use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
 use rustc_index::IndexVec;
@@ -30,21 +13,30 @@ use rustc_middle::lint::{
 };
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
-use rustc_session::lint::{
-    builtin::{
-        self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
-        UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
-    },
-    Level, Lint, LintExpectationId, LintId,
+use rustc_session::lint::builtin::{
+    self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
+    UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
 };
+use rustc_session::lint::{Level, Lint, LintExpectationId, LintId};
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use tracing::{debug, instrument};
+use {rustc_ast as ast, rustc_hir as hir};
 
+use crate::builtin::MISSING_DOCS;
+use crate::context::{CheckLintNameResult, LintStore};
 use crate::errors::{
-    MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub,
-    UnknownToolInScopedLint,
+    CheckNameUnknownTool, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
+    OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
+};
+use crate::fluent_generated as fluent;
+use crate::late::unerased_lint_store;
+use crate::lints::{
+    DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
+    OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint,
+    RenamedLintFromCommandLine, RenamedLintSuggestion, UnknownLint, UnknownLintFromCommandLine,
+    UnknownLintSuggestion,
 };
 
 /// Collection of lint levels for the whole crate.
@@ -725,7 +717,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
         };
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) {
         let sess = self.sess;
         for (attr_index, attr) in attrs.iter().enumerate() {
@@ -1047,7 +1038,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
             let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
             // FIXME: make this translatable
             #[allow(rustc::diagnostic_outside_of_impl)]
-            #[allow(rustc::untranslatable_diagnostic)]
             lint_level(self.sess, lint, level, src, Some(span.into()), |lint| {
                 lint.primary_message(fluent::lint_unknown_gated_lint);
                 lint.arg("name", lint_id.lint.name_lower());
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 7c44d16169e..4f3933d461b 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -83,12 +83,6 @@ mod types;
 mod unit_bindings;
 mod unused;
 
-pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
-
-use rustc_hir::def_id::LocalModDefId;
-use rustc_middle::query::Providers;
-use rustc_middle::ty::TyCtxt;
-
 use async_closures::AsyncClosureUsage;
 use async_fn_in_trait::AsyncFnInTrait;
 use builtin::*;
@@ -116,7 +110,11 @@ use precedence::*;
 use ptr_nulls::*;
 use redundant_semicolon::*;
 use reference_casting::*;
+use rustc_hir::def_id::LocalModDefId;
+use rustc_middle::query::Providers;
+use rustc_middle::ty::TyCtxt;
 use shadowed_into_iter::ShadowedIntoIter;
+pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 use traits::*;
 use types::*;
 use unit_bindings::*;
@@ -124,14 +122,16 @@ use unused::*;
 
 #[rustfmt::skip]
 pub use builtin::{MissingDoc, SoftLints};
-pub use context::{CheckLintNameResult, FindLintError, LintStore};
-pub use context::{EarlyContext, LateContext, LintContext};
+pub use context::{
+    CheckLintNameResult, EarlyContext, FindLintError, LateContext, LintContext, LintStore,
+};
 pub use early::{check_ast_node, EarlyCheckNode};
 pub use late::{check_crate, late_lint_mod, unerased_lint_store};
 pub use passes::{EarlyLintPass, LateLintPass};
 pub use rustc_session::lint::Level::{self, *};
-pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
-pub use rustc_session::lint::{LintPass, LintVec};
+pub use rustc_session::lint::{
+    BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec,
+};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
@@ -543,7 +543,7 @@ fn register_builtins(store: &mut LintStore) {
     );
     store.register_removed(
         "suspicious_auto_trait_impls",
-        "no longer needed, see #93367 \
+        "no longer needed, see issue #93367 \
          <https://github.com/rust-lang/rust/issues/93367> for more information",
     );
     store.register_removed(
@@ -565,6 +565,11 @@ fn register_builtins(store: &mut LintStore) {
         "box_pointers",
         "it does not detect other kinds of allocations, and existed only for historical reasons",
     );
+    store.register_removed(
+        "byte_slice_in_packed_struct_with_derive",
+        "converted into hard error, see issue #107457 \
+         <https://github.com/rust-lang/rust/issues/107457> for more information",
+    )
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index b669a3c6288..03962d796f4 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2,27 +2,26 @@
 #![allow(rustc::untranslatable_diagnostic)]
 use std::num::NonZero;
 
-use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
-use crate::errors::{OverruledAttributeSub, RequestedLevel};
-use crate::fluent_generated as fluent;
-use crate::LateContext;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
-    ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp,
-    Subdiagnostic, SuggestionStyle,
+    Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
+    EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
 };
-use rustc_hir::{self as hir, def::Namespace, def_id::DefId};
+use rustc_hir::def::Namespace;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir};
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
-use rustc_middle::ty::{
-    inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
-};
-use rustc_session::{lint::AmbiguityErrorDiag, Session};
-use rustc_span::{
-    edition::Edition,
-    sym,
-    symbol::{Ident, MacroRulesNormalizedIdent},
-    Span, Symbol,
-};
+use rustc_middle::ty::inhabitedness::InhabitedPredicate;
+use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_session::lint::AmbiguityErrorDiag;
+use rustc_session::Session;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
+use rustc_span::{sym, Span, Symbol};
+
+use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
+use crate::errors::{OverruledAttributeSub, RequestedLevel};
+use crate::{fluent_generated as fluent, LateContext};
 
 // array_into_iter.rs
 #[derive(LintDiagnostic)]
@@ -958,6 +957,8 @@ pub struct BadOptAccessDiag<'a> {
 pub enum NonBindingLet {
     #[diag(lint_non_binding_let_on_sync_lock)]
     SyncLock {
+        #[label]
+        pat: Span,
         #[subdiagnostic]
         sub: NonBindingLetSub,
     },
@@ -2379,6 +2380,16 @@ pub mod unexpected_cfg_value {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_unexpected_builtin_cfg)]
+#[note(lint_controlled_by)]
+#[note(lint_incoherent)]
+pub struct UnexpectedBuiltinCfg {
+    pub(crate) cfg: String,
+    pub(crate) cfg_name: Symbol,
+    pub(crate) controlled_by: &'static str,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_macro_use_deprecated)]
 #[help]
 pub struct MacroUseDeprecated;
diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
index 867e132b106..e3b1967da09 100644
--- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
+++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
@@ -1,16 +1,12 @@
-//! Migration code for the `expr_fragment_specifier_2024`
-//! rule.
-use tracing::debug;
+//! Migration code for the `expr_fragment_specifier_2024` rule.
 
-use rustc_ast::token::Token;
-use rustc_ast::token::TokenKind;
-use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::tokenstream::TokenTree;
-use rustc_session::declare_lint;
-use rustc_session::declare_lint_pass;
+use rustc_ast::token::{Token, TokenKind};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_session::lint::FutureIncompatibilityReason;
+use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::sym;
+use tracing::debug;
 
 use crate::lints::MacroExprFragment2024;
 use crate::EarlyLintPass;
diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs
index e355604e206..3b27e456136 100644
--- a/compiler/rustc_lint/src/map_unit_fn.rs
+++ b/compiler/rustc_lint/src/map_unit_fn.rs
@@ -1,13 +1,11 @@
-use crate::lints::MappingToUnit;
-use crate::{LateContext, LateLintPass, LintContext};
-
 use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind};
-use rustc_middle::{
-    query::Key,
-    ty::{self, Ty},
-};
+use rustc_middle::query::Key;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint, declare_lint_pass};
 
+use crate::lints::MappingToUnit;
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `map_unit_fn` lint checks for `Iterator::map` receive
     /// a callable that returns `()`.
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index 7a71fec769f..dff72bb622f 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -1,11 +1,11 @@
-use crate::lints::CStringPtr;
-use crate::LateContext;
-use crate::LateLintPass;
-use crate::LintContext;
 use rustc_hir::{Expr, ExprKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+use crate::lints::CStringPtr;
+use crate::{LateContext, LateLintPass, LintContext};
 
 declare_lint! {
     /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 93dd5e764c6..978109aba5f 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -1,8 +1,8 @@
-use crate::{LateContext, LateLintPass, LintContext};
-
 use rustc_hir as hir;
 use rustc_session::{declare_lint, declare_lint_pass};
 
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
     /// supertraits.
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 9f298a6071c..08d054b6a8b 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -1,8 +1,3 @@
-use crate::lints::{
-    ConfusableIdentifierPair, IdentifierNonAsciiChar, IdentifierUncommonCodepoints,
-    MixedScriptConfusables,
-};
-use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::UnordMap;
@@ -10,6 +5,12 @@ use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::symbol::Symbol;
 use unicode_security::general_security_profile::IdentifierType;
 
+use crate::lints::{
+    ConfusableIdentifierPair, IdentifierNonAsciiChar, IdentifierUncommonCodepoints,
+    MixedScriptConfusables,
+};
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+
 declare_lint! {
     /// The `non_ascii_idents` lint detects non-ASCII identifiers.
     ///
@@ -152,9 +153,10 @@ declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CON
 
 impl EarlyLintPass for NonAsciiIdents {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
+        use std::collections::BTreeMap;
+
         use rustc_session::lint::Level;
         use rustc_span::Span;
-        use std::collections::BTreeMap;
         use unicode_security::GeneralSecurityProfile;
 
         let check_non_ascii_idents = cx.builder.lint_level(NON_ASCII_IDENTS).0 != Level::Allow;
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 2dc2a0efdf0..10a517bfbcb 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -1,19 +1,20 @@
-use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
-use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::bug;
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_parse_format::{ParseMode, Parser, Piece};
 use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::edition::Edition;
-use rustc_span::{hygiene, sym, symbol::kw, InnerSpan, Span, Symbol};
+use rustc_span::symbol::kw;
+use rustc_span::{hygiene, sym, InnerSpan, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
 
+use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
+use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
     /// argument is not a formatting string.
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 93c606a954e..5ad677995da 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -1,24 +1,23 @@
 use rustc_errors::MultiSpan;
+use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::HirId;
-use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind};
-use rustc_hir::{Path, QPath};
+use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, QPath, TyKind};
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::{Obligation, ObligationCause};
-use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable, TypeFolder};
-use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, Binder, EarlyBinder, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+};
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
-use rustc_span::Span;
-use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind, Symbol};
+use rustc_span::symbol::kw;
+use rustc_span::{sym, ExpnKind, MacroKind, Span, Symbol};
 use rustc_trait_selection::error_reporting::traits::ambiguity::{
     compute_applicable_impls_for_diagnostics, CandidateSource,
 };
 use rustc_trait_selection::infer::TyCtxtInferExt;
 
-use crate::fluent_generated as fluent;
 use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
-use crate::{LateContext, LateLintPass, LintContext};
+use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext};
 
 declare_lint! {
     /// The `non_local_definitions` lint checks for `impl` blocks and `#[macro_export]`
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index d64f4447162..d7fd41c0ad7 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,11 +1,3 @@
-use crate::lints::{
-    NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub,
-    NonUpperCaseGlobal, NonUpperCaseGlobalSub,
-};
-use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_ast as ast;
-use rustc_attr as attr;
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{GenericParamKind, PatKind};
@@ -16,6 +8,13 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{BytePos, Span};
 use rustc_target::spec::abi::Abi;
+use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
+
+use crate::lints::{
+    NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub,
+    NonUpperCaseGlobal, NonUpperCaseGlobalSub,
+};
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 
 #[derive(PartialEq)]
 pub enum MethodLateContext {
@@ -528,11 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
         // Lint for constants that look like binding identifiers (#7526)
         if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
             if let Res::Def(DefKind::Const, _) = path.res {
-                if path.segments.len() == 1 {
+                if let [segment] = path.segments {
                     NonUpperCaseGlobals::check_upper_case(
                         cx,
                         "constant in pattern",
-                        &path.segments[0].ident,
+                        &segment.ident,
                     );
                 }
             }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 307e4bebe9a..d08a959f654 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,9 +1,3 @@
-use crate::context::LintContext;
-use crate::lints::{
-    NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag,
-};
-use crate::LateContext;
-use crate::LateLintPass;
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_middle::ty;
@@ -11,6 +5,12 @@ use rustc_middle::ty::adjustment::Adjust;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::symbol::sym;
 
+use crate::context::LintContext;
+use crate::lints::{
+    NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag,
+};
+use crate::{LateContext, LateLintPass};
+
 declare_lint! {
     /// The `noop_method_call` lint detects specific calls to noop methods
     /// such as a calling `<&T as Clone>::clone` where `T: !Clone`.
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index fdb71ad41a7..e0ba6a912f1 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -1,10 +1,12 @@
 use rustc_hir as hir;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
+use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifiersAndPath};
-use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::{symbol::kw, Span};
+use rustc_span::symbol::kw;
+use rustc_span::Span;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 use crate::{LateContext, LateLintPass, LintContext};
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index fa23f120468..23b200998a5 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -1,5 +1,3 @@
-use crate::lints::PassByValueDiag;
-use crate::{LateContext, LateLintPass, LintContext};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
@@ -7,6 +5,9 @@ use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
 
+use crate::lints::PassByValueDiag;
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_tool_lint! {
     /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to
     /// always be passed by value. This is usually used for types that are thin wrappers around
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 2a843977990..bf16e3b7d15 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -1,8 +1,8 @@
-use crate::context::{EarlyContext, LateContext};
-
 use rustc_session::lint::builtin::HardwiredLints;
 use rustc_session::lint::LintPass;
 
+use crate::context::{EarlyContext, LateContext};
+
 #[macro_export]
 macro_rules! late_lint_methods {
     ($macro:path, $args:tt) => (
diff --git a/compiler/rustc_lint/src/precedence.rs b/compiler/rustc_lint/src/precedence.rs
index eb2ba397277..52321e25c7d 100644
--- a/compiler/rustc_lint/src/precedence.rs
+++ b/compiler/rustc_lint/src/precedence.rs
@@ -16,6 +16,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![deny(ambiguous_negative_literals)]
     /// # #![allow(unused)]
     /// -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1
     /// ```
@@ -27,7 +28,7 @@ declare_lint! {
     /// Method calls take precedence over unary precedence. Setting the
     /// precedence explicitly makes the code clearer and avoid potential bugs.
     pub AMBIGUOUS_NEGATIVE_LITERALS,
-    Deny,
+    Allow,
     "ambiguous negative literals operations",
     report_in_external_macro
 }
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 8038115ef51..1489f9de819 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -1,9 +1,11 @@
-use crate::{lints::PtrNullChecksDiag, LateContext, LateLintPass, LintContext};
 use rustc_ast::LitKind;
 use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::sym;
 
+use crate::lints::PtrNullChecksDiag;
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `useless_ptr_null_checks` lint checks for useless null checks against pointers
     /// obtained from non-null types.
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index ef08e79e24a..b43e4938b73 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -1,8 +1,10 @@
-use crate::{lints::RedundantSemicolonsDiag, EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::{Block, StmtKind};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::Span;
 
+use crate::lints::RedundantSemicolonsDiag;
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+
 declare_lint! {
     /// The `redundant_semicolons` lint detects unnecessary trailing
     /// semicolons.
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 34153e3a220..5e8c39c0023 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -1,11 +1,12 @@
 use rustc_ast::Mutability;
 use rustc_hir::{Expr, ExprKind, UnOp};
-use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::{self, layout::TyAndLayout};
+use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout};
+use rustc_middle::ty::{self};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::sym;
 
-use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
+use crate::lints::InvalidReferenceCastingDiag;
+use crate::{LateContext, LateLintPass, LintContext};
 
 declare_lint! {
     /// The `invalid_reference_casting` lint checks for casts of `&T` to `&mut T`
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
index da2b5878b19..4fe35a6a0a3 100644
--- a/compiler/rustc_lint/src/shadowed_into_iter.rs
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -1,11 +1,12 @@
-use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub};
-use crate::{LateContext, LateLintPass, LintContext};
 use rustc_hir as hir;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::edition::Edition;
 
+use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub};
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `array_into_iter` lint detects calling `into_iter` on arrays.
     ///
diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs
index 4fd054cb717..988d1645fba 100644
--- a/compiler/rustc_lint/src/tests.rs
+++ b/compiler/rustc_lint/src/tests.rs
@@ -1,6 +1,7 @@
-use crate::levels::parse_lint_and_tool_name;
 use rustc_span::{create_default_session_globals_then, Symbol};
 
+use crate::levels::parse_lint_and_tool_name;
+
 #[test]
 fn parse_lint_no_tool() {
     create_default_session_globals_then(|| {
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 552245f0cdd..fea96b5366e 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -1,11 +1,10 @@
-use crate::lints::{DropGlue, DropTraitConstraintsDiag};
-use crate::LateContext;
-use crate::LateLintPass;
-use crate::LintContext;
 use rustc_hir::{self as hir, LangItem};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::symbol::sym;
 
+use crate::lints::{DropGlue, DropTraitConstraintsDiag};
+use crate::{LateContext, LateLintPass, LintContext};
+
 declare_lint! {
     /// The `drop_bounds` lint checks for generics with `std::ops::Drop` as
     /// bounds.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index c0364b35716..51896da893c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,39 +1,33 @@
-use crate::{
-    fluent_generated as fluent,
-    lints::{
-        AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
-        AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
-        AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
-        InvalidNanComparisonsSuggestion, OnlyCastu8ToChar, OverflowingBinHex,
-        OverflowingBinHexSign, OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt,
-        OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange,
-        UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag,
-    },
-};
-use crate::{LateContext, LateLintPass, LintContext};
-use rustc_ast as ast;
-use rustc_attr as attr;
+use std::iter;
+use std::ops::ControlFlow;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagMessage;
-use rustc_hir as hir;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
-use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{
-    self, AdtKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol};
-use rustc_target::abi::{Abi, Size, WrappingRange};
-use rustc_target::abi::{Integer, TagEncoding, Variants};
+use rustc_span::{source_map, Span, Symbol};
+use rustc_target::abi::{Abi, Integer, Size, TagEncoding, Variants, WrappingRange};
 use rustc_target::spec::abi::Abi as SpecAbi;
-use std::iter;
-use std::ops::ControlFlow;
 use tracing::debug;
+use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
+
+use crate::lints::{
+    AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
+    AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
+    AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
+    InvalidNanComparisonsSuggestion, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
+    OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp,
+    OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons,
+    UseInclusiveRange, VariantSizeDifferencesDiag,
+};
+use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext};
 
 declare_lint! {
     /// The `unused_comparisons` lint detects comparisons made useless by
@@ -217,15 +211,12 @@ fn lint_overflowing_range_endpoint<'tcx>(
     if !is_range_literal(struct_expr) {
         return false;
     };
-    let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false };
-    if eps.len() != 2 {
-        return false;
-    }
+    let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false };
 
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
     // overflowing and only by 1.
-    if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
+    if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) {
         return false;
     };
 
@@ -238,7 +229,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
     };
 
     let sub_sugg = if expr.span.lo() == lit_span.lo() {
-        let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
+        let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
         UseInclusiveRange::WithoutParen {
             sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
             start,
@@ -315,11 +306,7 @@ fn report_bin_hex_error(
 ) {
     let (t, actually) = match ty {
         attr::IntType::SignedInt(t) => {
-            let actually = if negative {
-                -(size.sign_extend(val) as i128)
-            } else {
-                size.sign_extend(val) as i128
-            };
+            let actually = if negative { -(size.sign_extend(val)) } else { size.sign_extend(val) };
             (t.name_str(), actually.to_string())
         }
         attr::IntType::UnsignedInt(t) => {
@@ -468,8 +455,11 @@ fn lint_int_literal<'tcx>(
         }
 
         let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span };
-        let lit =
-            cx.sess().source_map().span_to_snippet(span).expect("must get snippet from literal");
+        let lit = cx
+            .sess()
+            .source_map()
+            .span_to_snippet(span)
+            .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() });
         let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
 
@@ -495,6 +485,7 @@ fn lint_uint_literal<'tcx>(
         ast::LitKind::Int(v, _) => v.get(),
         _ => bug!(),
     };
+
     if lit_val < min || lit_val > max {
         if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) {
             match par_e.kind {
@@ -536,7 +527,7 @@ fn lint_uint_literal<'tcx>(
                     .sess()
                     .source_map()
                     .span_to_snippet(lit.span)
-                    .expect("must get snippet from literal"),
+                    .unwrap_or_else(|_| lit_val.to_string()),
                 min,
                 max,
             },
@@ -561,14 +552,14 @@ fn lint_literal<'tcx>(
         }
         ty::Uint(t) => lint_uint_literal(cx, e, lit, t),
         ty::Float(t) => {
-            let is_infinite = match lit.node {
+            let (is_infinite, sym) = match lit.node {
                 ast::LitKind::Float(v, _) => match t {
                     // FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI
                     // issues resolved).
-                    ty::FloatTy::F16 => Ok(false),
-                    ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
-                    ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
-                    ty::FloatTy::F128 => Ok(false),
+                    ty::FloatTy::F16 => (Ok(false), v),
+                    ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v),
+                    ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v),
+                    ty::FloatTy::F128 => (Ok(false), v),
                 },
                 _ => bug!(),
             };
@@ -582,7 +573,7 @@ fn lint_literal<'tcx>(
                             .sess()
                             .source_map()
                             .span_to_snippet(lit.span)
-                            .expect("must get snippet from literal"),
+                            .unwrap_or_else(|_| sym.to_string()),
                     },
                 );
             }
diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs
index 8202bfa805a..ed015908ae5 100644
--- a/compiler/rustc_lint/src/unit_bindings.rs
+++ b/compiler/rustc_lint/src/unit_bindings.rs
@@ -1,8 +1,9 @@
-use crate::lints::UnitBindingsDiag;
-use crate::{LateLintPass, LintContext};
 use rustc_hir as hir;
 use rustc_session::{declare_lint, declare_lint_pass};
 
+use crate::lints::UnitBindingsDiag;
+use crate::{LateLintPass, LintContext};
+
 declare_lint! {
     /// The `unit_bindings` lint detects cases where bindings are useless because they have
     /// the unit type `()` as their inferred type. The lint is suppressed if the user explicitly
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 65d42ed8054..553d9db12c5 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1,11 +1,6 @@
-use crate::lints::{
-    PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
-    UnusedAllocationMutDiag, UnusedClosure, UnusedCoroutine, UnusedDef, UnusedDefSuggestion,
-    UnusedDelim, UnusedDelimSuggestion, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
-    UnusedResult,
-};
-use crate::Lint;
-use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use std::iter;
+use std::ops::ControlFlow;
+
 use rustc_ast as ast;
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{ExprKind, StmtKind};
@@ -14,16 +9,20 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
 use rustc_infer::traits::util::elaborate;
-use rustc_middle::ty::adjustment;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, adjustment, Ty};
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
-use rustc_span::symbol::Symbol;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, Span};
-use std::iter;
-use std::ops::ControlFlow;
 use tracing::instrument;
 
+use crate::lints::{
+    PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
+    UnusedAllocationMutDiag, UnusedClosure, UnusedCoroutine, UnusedDef, UnusedDefSuggestion,
+    UnusedDelim, UnusedDelimSuggestion, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
+    UnusedResult,
+};
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Lint, LintContext};
+
 declare_lint! {
     /// The `unused_must_use` lint detects unused result of a type flagged as
     /// `#[must_use]`.
@@ -676,6 +675,13 @@ trait UnusedDelimLint {
             return true;
         }
 
+        // Do not lint against parentheses around `&raw [const|mut] expr`.
+        // These parentheses will have to be added e.g. when calling a method on the result of this
+        // expression, and we want to avoid churn wrt adding and removing parentheses.
+        if matches!(inner.kind, ast::ExprKind::AddrOf(ast::BorrowKind::Raw, ..)) {
+            return true;
+        }
+
         // Check if LHS needs parens to prevent false-positives in cases like
         // `fn x() -> u8 { ({ 0 } + 1) }`.
         //
@@ -802,7 +808,7 @@ trait UnusedDelimLint {
             return;
         }
         let spans = match value.kind {
-            ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0]
+            ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => stmt
                 .span
                 .find_ancestor_inside(value.span)
                 .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
@@ -1205,7 +1211,8 @@ impl EarlyLintPass for UnusedParens {
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
-        use ast::{Mutability, PatKind::*};
+        use ast::Mutability;
+        use ast::PatKind::*;
         let keep_space = (false, false);
         match &p.kind {
             // Do not lint on `(..)` as that will result in the other arms being useless.
@@ -1537,14 +1544,12 @@ impl UnusedImportBraces {
             }
 
             // Trigger the lint only if there is one nested item
-            if items.len() != 1 {
-                return;
-            }
+            let [(tree, _)] = items.as_slice() else { return };
 
             // Trigger the lint if the nested item is a non-self single item
-            let node_name = match items[0].0.kind {
+            let node_name = match tree.kind {
                 ast::UseTreeKind::Simple(rename) => {
-                    let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
+                    let orig_ident = tree.prefix.segments.last().unwrap().ident;
                     if orig_ident.name == kw::SelfLower {
                         return;
                     }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c4158cccca4..c731b03a875 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -7,9 +7,10 @@
 //! When removing a lint, make sure to also add a call to `register_removed` in
 //! compiler/rustc_lint/src/lib.rs.
 
-use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 
+use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -25,7 +26,6 @@ declare_lint_pass! {
         BARE_TRAIT_OBJECTS,
         BINDINGS_WITH_VARIANT_NAME,
         BREAK_WITH_LABEL_AND_LOOP,
-        BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
         CENUM_IMPL_DROP_CAST,
         COHERENCE_LEAK_CHECK,
         CONFLICTING_REPR_HINTS,
@@ -42,6 +42,7 @@ declare_lint_pass! {
         DUPLICATE_MACRO_ATTRIBUTES,
         ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
         ELIDED_LIFETIMES_IN_PATHS,
+        EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
         EXPORTED_PRIVATE_DEPENDENCIES,
         FFI_UNWIND_CALLS,
         FORBIDDEN_LINT_GROUPS,
@@ -81,6 +82,7 @@ declare_lint_pass! {
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         PTR_CAST_ADD_AUTO_TO_OBJECT,
         PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+        REDUNDANT_IMPORTS,
         REDUNDANT_LIFETIMES,
         REFINING_IMPL_TRAIT_INTERNAL,
         REFINING_IMPL_TRAIT_REACHABLE,
@@ -91,6 +93,7 @@ declare_lint_pass! {
         RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
         RUST_2021_PRELUDE_COLLISIONS,
         RUST_2024_INCOMPATIBLE_PAT,
+        RUST_2024_PRELUDE_COLLISIONS,
         SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
         SINGLE_USE_LIFETIMES,
@@ -425,6 +428,31 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `redundant_imports` lint detects imports that are redundant due to being
+    /// imported already; either through a previous import, or being present in
+    /// the prelude.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(redundant_imports)]
+    /// use std::option::Option::None;
+    /// fn foo() -> Option<i32> { None }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Redundant imports are unnecessary and can be removed to simplify code.
+    /// If you intended to re-export the item to make it available outside of the
+    /// module, add a visibility modifier like `pub`.
+    pub REDUNDANT_IMPORTS,
+    Allow,
+    "imports that are redundant due to being imported already"
+}
+
+declare_lint! {
     /// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points
     /// (`.await`)
     ///
@@ -615,8 +643,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
-    /// #![cfg_attr(bootstrap, feature(lint_reasons))]
-    ///
     /// #[expect(unused_variables)]
     /// let x = 10;
     /// println!("{}", x);
@@ -1241,7 +1267,7 @@ declare_lint! {
     Deny,
     "type parameter default erroneously allowed in invalid location",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
     };
 }
@@ -1834,8 +1860,7 @@ declare_lint! {
     /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions
     pub ELIDED_LIFETIMES_IN_PATHS,
     Allow,
-    "hidden lifetime parameters in types are deprecated",
-    crate_level_only
+    "hidden lifetime parameters in types are deprecated"
 }
 
 declare_lint! {
@@ -3265,6 +3290,39 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `explicit_builtin_cfgs_in_flags` lint detects builtin cfgs set via the `--cfg` flag.
+    ///
+    /// ### Example
+    ///
+    /// ```text
+    /// rustc --cfg unix
+    /// ```
+    ///
+    /// ```rust,ignore (needs command line option)
+    /// fn main() {}
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: unexpected `--cfg unix` flag
+    ///   |
+    ///   = note: config `unix` is only supposed to be controlled by `--target`
+    ///   = note: manually setting a built-in cfg can and does create incoherent behaviors
+    ///   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Setting builtin cfgs can and does produce incoherent behavior, it's better to the use
+    /// the appropriate `rustc` flag that controls the config. For example setting the `windows`
+    /// cfg but on Linux based target.
+    pub EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
+    Deny,
+    "detects builtin cfgs set via the `--cfg`"
+}
+
+declare_lint! {
     /// The `repr_transparent_external_private_fields` lint
     /// detects types marked `#[repr(transparent)]` that (transitively)
     /// contain an external ZST type marked `#[non_exhaustive]` or containing
@@ -3755,6 +3813,46 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `rust_2024_prelude_collisions` lint detects the usage of trait methods which are ambiguous
+    /// with traits added to the prelude in future editions.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2021,compile_fail
+    /// #![deny(rust_2024_prelude_collisions)]
+    /// trait Meow {
+    ///     fn poll(&self) {}
+    /// }
+    /// impl<T> Meow for T {}
+    ///
+    /// fn main() {
+    ///     core::pin::pin!(async {}).poll();
+    ///     //                        ^^^^^^
+    ///     // This call to try_into matches both Future::poll and Meow::poll as
+    ///     // `Future` has been added to the Rust prelude in 2024 edition.
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust 2024, introduces two new additions to the standard library's prelude:
+    /// `Future` and `IntoFuture`. This results in an ambiguity as to which method/function
+    /// to call when an existing `poll`/`into_future` method is called via dot-call syntax or
+    /// a `poll`/`into_future` associated function is called directly on a type.
+    ///
+    pub RUST_2024_PRELUDE_COLLISIONS,
+    Allow,
+    "detects the usage of trait methods which are ambiguous with traits added to the \
+        prelude in future editions",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>",
+    };
+}
+
+declare_lint! {
     /// The `rust_2021_prefixes_incompatible_syntax` lint detects identifiers that will be parsed as a
     /// prefix instead in Rust 2021.
     ///
@@ -4251,39 +4349,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
-    /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or
-    /// more built-in traits.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// #[repr(packed)]
-    /// #[derive(Hash)]
-    /// struct FlexZeroSlice {
-    ///     width: u8,
-    ///     data: [u8],
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// This was previously accepted but is being phased out, because fields in packed structs are
-    /// now required to implement `Copy` for `derive` to work. Byte slices and string slices are a
-    /// temporary exception because certain crates depended on them.
-    pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
-    Warn,
-    "`[u8]` or `str` used in a packed struct with `derive`",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
-    };
-    report_in_external_macro
-}
-
-declare_lint! {
     /// The `invalid_macro_export_arguments` lint detects cases where `#[macro_export]` is being used with invalid arguments.
     ///
     /// ### Example
@@ -4869,7 +4934,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
-    /// #![feature(unsafe_extern_blocks)]
     /// #![warn(missing_unsafe_on_extern)]
     /// #![allow(dead_code)]
     ///
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index f87f19e1700..0f07de43e80 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -1,4 +1,3 @@
-pub use self::Level::*;
 use rustc_ast::node_id::NodeId;
 use rustc_ast::{AttrId, Attribute};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -7,16 +6,16 @@ use rustc_data_structures::stable_hasher::{
 };
 use rustc_error_messages::{DiagMessage, MultiSpan};
 use rustc_hir::def::Namespace;
-use rustc_hir::HashStableContext;
-use rustc_hir::HirId;
+use rustc_hir::{HashStableContext, HirId};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::edition::Edition;
-use rustc_span::symbol::MacroRulesNormalizedIdent;
-use rustc_span::{sym, symbol::Ident, Span, Symbol};
+use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
+use rustc_span::{sym, Span, Symbol};
 use rustc_target::spec::abi::Abi;
-
 use serde::{Deserialize, Serialize};
 
+pub use self::Level::*;
+
 pub mod builtin;
 
 #[macro_export]
@@ -747,6 +746,11 @@ pub enum BuiltinLintDiag {
     OutOfScopeMacroCalls {
         path: String,
     },
+    UnexpectedBuiltinCfg {
+        cfg: String,
+        cfg_name: Symbol,
+        controlled_by: &'static str,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
@@ -754,7 +758,7 @@ pub enum BuiltinLintDiag {
 #[derive(Debug)]
 pub struct BufferedEarlyLint {
     /// The span of code that we are linting on.
-    pub span: MultiSpan,
+    pub span: Option<MultiSpan>,
 
     /// The `NodeId` of the AST node that generated the lint.
     pub node_id: NodeId,
@@ -792,7 +796,7 @@ impl LintBuffer {
         self.add_early_lint(BufferedEarlyLint {
             lint_id: LintId::of(lint),
             node_id,
-            span: span.into(),
+            span: Some(span.into()),
             diagnostic,
         });
     }
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 4c1f78e6bee..b2ff9efb41c 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -259,6 +259,7 @@ fn main() {
     cmd.args(&components);
 
     for lib in output(&mut cmd).split_whitespace() {
+        let mut is_static = false;
         let name = if let Some(stripped) = lib.strip_prefix("-l") {
             stripped
         } else if let Some(stripped) = lib.strip_prefix('-') {
@@ -266,8 +267,24 @@ fn main() {
         } else if Path::new(lib).exists() {
             // On MSVC llvm-config will print the full name to libraries, but
             // we're only interested in the name part
-            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
-            name.trim_end_matches(".lib")
+            // On Unix when we get a static library llvm-config will print the
+            // full name and we *are* interested in the path, but we need to
+            // handle it separately. For example, when statically linking to
+            // libzstd llvm-config will output something like
+            //   -lrt -ldl -lm -lz /usr/local/lib/libzstd.a -lxml2
+            // and we transform the zstd part into
+            //   cargo:rustc-link-search-native=/usr/local/lib
+            //   cargo:rustc-link-lib=static=zstd
+            let path = Path::new(lib);
+            if lib.ends_with(".a") {
+                is_static = true;
+                println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
+                let name = path.file_stem().unwrap().to_str().unwrap();
+                name.trim_start_matches("lib")
+            } else {
+                let name = path.file_name().unwrap().to_str().unwrap();
+                name.trim_end_matches(".lib")
+            }
         } else if lib.ends_with(".lib") {
             // Some MSVC libraries just come up with `.lib` tacked on, so chop
             // that off
@@ -285,7 +302,13 @@ fn main() {
             continue;
         }
 
-        let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
+        let kind = if name.starts_with("LLVM") {
+            llvm_kind
+        } else if is_static {
+            "static"
+        } else {
+            "dylib"
+        };
         println!("cargo:rustc-link-lib={kind}={name}");
     }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 4cdd8af1008..79a68b2ff0e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -397,6 +397,18 @@ LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {
                                               std::nullopt));
 }
 
+extern "C" LLVMAttributeRef
+LLVMRustCreateRangeAttribute(LLVMContextRef C, unsigned NumBits,
+                             const uint64_t LowerWords[],
+                             const uint64_t UpperWords[]) {
+#if LLVM_VERSION_GE(19, 0)
+  return LLVMCreateConstantRangeAttribute(C, Attribute::Range, NumBits,
+                                          LowerWords, UpperWords);
+#else
+  report_fatal_error("LLVM 19.0 is required for Range Attribute");
+#endif
+}
+
 // These values **must** match ffi::AllocKindFlags.
 // It _happens_ to match the LLVM values of llvm::AllocFnKind,
 // but that's happenstance and we do explicit conversions before
@@ -1555,7 +1567,7 @@ LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) {
 
 extern "C" LLVMValueRef
 LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_GE(18, 0)
+#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0)
   return wrap(llvm::Intrinsic::getDeclaration(
       unwrap(M), llvm::Intrinsic::instrprof_mcdc_condbitmap_update));
 #else
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 1365afbce1c..939e5e4dbd4 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -7,10 +7,11 @@
 
 // NOTE: This crate only exists to allow linking on mingw targets.
 
-use libc::{c_char, size_t};
 use std::cell::RefCell;
 use std::slice;
 
+use libc::{c_char, size_t};
+
 #[repr(C)]
 pub struct RustString {
     pub bytes: RefCell<Vec<u8>>,
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 01b6e342df0..b6d870768a8 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -41,12 +41,11 @@
 use std::env::{self, VarError};
 use std::fmt::{self, Display};
 use std::io::{self, IsTerminal};
+
 use tracing_core::{Event, Subscriber};
 use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
-use tracing_subscriber::fmt::{
-    format::{self, FormatEvent, FormatFields},
-    FmtContext,
-};
+use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields};
+use tracing_subscriber::fmt::FmtContext;
 use tracing_subscriber::layer::SubscriberExt;
 
 /// The values of all the environment variables that matter for configuring a logger.
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 2743660ab89..52d892a20f4 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -2,14 +2,15 @@
 
 use std::cell::RefCell;
 
-use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
-use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
-use crate::diagnostics::utils::SetOnce;
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::spanned::Spanned;
 use synstructure::Structure;
 
+use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
+use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
+use crate::diagnostics::utils::SetOnce;
+
 /// The central struct for constructing the `into_diag` method from an annotated struct.
 pub(crate) struct DiagnosticDerive<'a> {
     structure: Structure<'a>,
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index f93d89d6c0f..5c2a429a1eb 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -1,5 +1,12 @@
 #![deny(unused_must_use)]
 
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::{format_ident, quote, quote_spanned};
+use syn::spanned::Spanned;
+use syn::{parse_quote, Attribute, Meta, Path, Token, Type};
+use synstructure::{BindingInfo, Structure, VariantInfo};
+
+use super::utils::SubdiagnosticVariant;
 use crate::diagnostics::error::{
     span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
 };
@@ -8,13 +15,6 @@ use crate::diagnostics::utils::{
     should_generate_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy,
     FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
-use proc_macro2::{Ident, Span, TokenStream};
-use quote::{format_ident, quote, quote_spanned};
-use syn::Token;
-use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
-use synstructure::{BindingInfo, Structure, VariantInfo};
-
-use super::utils::SubdiagnosticVariant;
 
 /// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
 #[derive(Clone, Copy, PartialEq, Eq)]
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index 13138ee4ab7..9cdb9fbab12 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -1,7 +1,8 @@
 use proc_macro::{Diagnostic, Level, MultiSpan};
 use proc_macro2::TokenStream;
 use quote::quote;
-use syn::{spanned::Spanned, Attribute, Error as SynError, Meta};
+use syn::spanned::Spanned;
+use syn::{Attribute, Error as SynError, Meta};
 
 #[derive(Debug)]
 pub(crate) enum DiagnosticDeriveError {
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 7f090f5ebc1..5d5d279eaf0 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -1,5 +1,12 @@
 #![deny(unused_must_use)]
 
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::spanned::Spanned;
+use syn::{Attribute, Meta, MetaList, Path};
+use synstructure::{BindingInfo, Structure, VariantInfo};
+
+use super::utils::SubdiagnosticVariant;
 use crate::diagnostics::error::{
     invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
 };
@@ -9,12 +16,6 @@ use crate::diagnostics::utils::{
     should_generate_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap,
     SetOnce, SpannedOption, SubdiagnosticKind,
 };
-use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
-use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
-use synstructure::{BindingInfo, Structure, VariantInfo};
-
-use super::utils::SubdiagnosticVariant;
 
 /// The central struct for constructing the `add_to_diag` method from an annotated struct.
 pub(crate) struct SubdiagnosticDerive {
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 05a5a32514b..0d3b2f52fa2 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -1,20 +1,21 @@
-use crate::diagnostics::error::{
-    span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
-};
-use proc_macro::Span;
-use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote, ToTokens};
 use std::cell::RefCell;
 use std::collections::{BTreeSet, HashMap};
 use std::fmt;
 use std::str::FromStr;
+
+use proc_macro::Span;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote, ToTokens};
 use syn::meta::ParseNestedMeta;
 use syn::punctuated::Punctuated;
-use syn::{parenthesized, LitStr, Path, Token};
-use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
+use syn::spanned::Spanned;
+use syn::{parenthesized, Attribute, Field, LitStr, Meta, Path, Token, Type, TypeTuple};
 use synstructure::{BindingInfo, VariantInfo};
 
 use super::error::invalid_attr;
+use crate::diagnostics::error::{
+    span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
+};
 
 thread_local! {
     pub(crate) static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 9d7418cd370..c59f86b0a9b 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -10,9 +10,8 @@
 #![feature(proc_macro_tracked_env)]
 // tidy-alphabetical-end
 
-use synstructure::decl_derive;
-
 use proc_macro::TokenStream;
+use synstructure::decl_derive;
 
 mod current_version;
 mod diagnostics;
diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs
index 488d4504a2d..6074c93d59c 100644
--- a/compiler/rustc_macros/src/symbols.rs
+++ b/compiler/rustc_macros/src/symbols.rs
@@ -24,11 +24,13 @@
 //! CFG_RELEASE="0.0.0" cargo +nightly expand > /tmp/rustc_span.rs
 //! ```
 
+use std::collections::HashMap;
+
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
-use std::collections::HashMap;
 use syn::parse::{Parse, ParseStream, Result};
-use syn::{braced, punctuated::Punctuated, Expr, Ident, Lit, LitStr, Macro, Token};
+use syn::punctuated::Punctuated;
+use syn::{braced, Expr, Ident, Lit, LitStr, Macro, Token};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 415399ed06c..d80aa0cc4f4 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -41,6 +41,9 @@ metadata_crate_dep_multiple =
 metadata_crate_dep_not_static =
     `{$crate_name}` was unavailable as a static crate, preventing fully static linking
 
+metadata_crate_dep_rustc_driver =
+    `feature(rustc_private)` is needed to link to the compiler's `rustc_driver` library
+
 metadata_crate_location_unknown_type =
     extern location for {$crate_name} is of an unknown type: {$path}
 
@@ -131,12 +134,18 @@ metadata_lib_framework_apple =
 metadata_lib_required =
     crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
 
+metadata_link_arg_unstable =
+    link kind `link-arg` is unstable
+
 metadata_link_cfg_form =
     link cfg must be of the form `cfg(/* predicate */)`
 
 metadata_link_cfg_single_predicate =
     link cfg must have a single predicate argument
 
+metadata_link_cfg_unstable =
+    link cfg is unstable
+
 metadata_link_framework_apple =
     link kind `framework` is only supported on Apple targets
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 749495bc2ef..14a1a7f67e5 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1,9 +1,13 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::errors;
-use crate::locator::{CrateError, CrateLocator, CratePaths};
-use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
+use std::error::Error;
+use std::ops::Fn;
+use std::path::Path;
+use std::str::FromStr;
+use std::time::Duration;
+use std::{cmp, env, iter};
 
+use proc_macro::bridge::client::ProcMacro;
 use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, AllocatorKind};
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::fx::FxHashSet;
@@ -29,13 +33,9 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::{PanicStrategy, Target, TargetTriple};
 use tracing::{debug, info, trace};
 
-use proc_macro::bridge::client::ProcMacro;
-use std::error::Error;
-use std::ops::Fn;
-use std::path::Path;
-use std::str::FromStr;
-use std::time::Duration;
-use std::{cmp, env, iter};
+use crate::errors;
+use crate::locator::{CrateError, CrateLocator, CratePaths};
+use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
 /// The backend's way to give the crate store access to the metadata in a library.
 /// Note that it returns the raw metadata bytes stored in the library file, whether
@@ -949,7 +949,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn report_unused_deps(&mut self, krate: &ast::Crate) {
         // Make a point span rather than covering the whole file
         let span = krate.spans.inner_span.shrink_to_lo();
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 9c69ab2344e..39fa23766b5 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -51,13 +51,7 @@
 //! Additionally, the algorithm is geared towards finding *any* solution rather
 //! than finding a number of solutions (there are normally quite a few).
 
-use crate::creader::CStore;
-use crate::errors::{
-    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
-    NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
-};
-
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::bug;
 use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
@@ -65,8 +59,16 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 use rustc_session::cstore::CrateDepKind;
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
+use rustc_span::sym;
 use tracing::info;
 
+use crate::creader::CStore;
+use crate::errors::{
+    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
+    NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcDriverHelp, RustcLibRequired,
+    TwoPanicRuntimes,
+};
+
 pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
     tcx.crate_types()
         .iter()
@@ -160,25 +162,49 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         Linkage::Dynamic | Linkage::IncludedFromDylib => {}
     }
 
+    let all_dylibs = || {
+        tcx.crates(()).iter().filter(|&&cnum| {
+            !tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some()
+        })
+    };
+
+    let mut upstream_in_dylibs = FxHashSet::default();
+
+    if tcx.features().rustc_private {
+        // We need this to prevent users of `rustc_driver` from linking dynamically to `std`
+        // which does not work as `std` is also statically linked into `rustc_driver`.
+
+        // Find all libraries statically linked to upstream dylibs.
+        for &cnum in all_dylibs() {
+            let deps = tcx.dylib_dependency_formats(cnum);
+            for &(depnum, style) in deps.iter() {
+                if let RequireStatic = style {
+                    upstream_in_dylibs.insert(depnum);
+                }
+            }
+        }
+    }
+
     let mut formats = FxHashMap::default();
 
     // Sweep all crates for found dylibs. Add all dylibs, as well as their
     // dependencies, ensuring there are no conflicts. The only valid case for a
     // dependency to be relied upon twice is for both cases to rely on a dylib.
-    for &cnum in tcx.crates(()).iter() {
-        if tcx.dep_kind(cnum).macros_only() {
+    for &cnum in all_dylibs() {
+        if upstream_in_dylibs.contains(&cnum) {
+            info!("skipping dylib: {}", tcx.crate_name(cnum));
+            // If this dylib is also available statically linked to another dylib
+            // we try to use that instead.
             continue;
         }
+
         let name = tcx.crate_name(cnum);
-        let src = tcx.used_crate_source(cnum);
-        if src.dylib.is_some() {
-            info!("adding dylib: {}", name);
-            add_library(tcx, cnum, RequireDynamic, &mut formats, &mut unavailable_as_static);
-            let deps = tcx.dylib_dependency_formats(cnum);
-            for &(depnum, style) in deps.iter() {
-                info!("adding {:?}: {}", style, tcx.crate_name(depnum));
-                add_library(tcx, depnum, style, &mut formats, &mut unavailable_as_static);
-            }
+        info!("adding dylib: {}", name);
+        add_library(tcx, cnum, RequireDynamic, &mut formats, &mut unavailable_as_static);
+        let deps = tcx.dylib_dependency_formats(cnum);
+        for &(depnum, style) in deps.iter() {
+            info!("adding {:?}: {}", style, tcx.crate_name(depnum));
+            add_library(tcx, depnum, style, &mut formats, &mut unavailable_as_static);
         }
     }
 
@@ -268,12 +294,15 @@ fn add_library(
             // This error is probably a little obscure, but I imagine that it
             // can be refined over time.
             if link2 != link || link == RequireStatic {
+                let linking_to_rustc_driver = tcx.sess.psess.unstable_features.is_nightly_build()
+                    && tcx.crates(()).iter().any(|&cnum| tcx.crate_name(cnum) == sym::rustc_driver);
                 tcx.dcx().emit_err(CrateDepMultiple {
                     crate_name: tcx.crate_name(cnum),
                     non_static_deps: unavailable_as_static
                         .drain(..)
                         .map(|cnum| NonStaticCrateDep { crate_name: tcx.crate_name(cnum) })
                         .collect(),
+                    rustc_driver_help: linking_to_rustc_driver.then_some(RustcDriverHelp),
                 });
             }
         }
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index b0d82a0e3b7..42dec978b78 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -1,9 +1,8 @@
-use std::{
-    io::Error,
-    path::{Path, PathBuf},
-};
+use std::io::Error;
+use std::path::{Path, PathBuf};
 
-use rustc_errors::{codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{sym, Span, Symbol};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
@@ -39,6 +38,8 @@ pub struct CrateDepMultiple {
     pub crate_name: Symbol,
     #[subdiagnostic]
     pub non_static_deps: Vec<NonStaticCrateDep>,
+    #[subdiagnostic]
+    pub rustc_driver_help: Option<RustcDriverHelp>,
 }
 
 #[derive(Subdiagnostic)]
@@ -47,6 +48,10 @@ pub struct NonStaticCrateDep {
     pub crate_name: Symbol,
 }
 
+#[derive(Subdiagnostic)]
+#[help(metadata_crate_dep_rustc_driver)]
+pub struct RustcDriverHelp;
+
 #[derive(Diagnostic)]
 #[diag(metadata_two_panic_runtimes)]
 pub struct TwoPanicRuntimes {
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs
index a0abda53eb3..b2a979ed6d8 100644
--- a/compiler/rustc_metadata/src/fs.rs
+++ b/compiler/rustc_metadata/src/fs.rs
@@ -1,8 +1,5 @@
-use crate::errors::{
-    BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
-    FailedCreateTempdir, FailedWriteError,
-};
-use crate::{encode_metadata, EncodedMetadata};
+use std::path::{Path, PathBuf};
+use std::{fs, io};
 
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_middle::ty::TyCtxt;
@@ -11,8 +8,11 @@ use rustc_session::output::filename_for_metadata;
 use rustc_session::{MetadataKind, Session};
 use tempfile::Builder as TempFileBuilder;
 
-use std::path::{Path, PathBuf};
-use std::{fs, io};
+use crate::errors::{
+    BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
+    FailedCreateTempdir, FailedWriteError,
+};
+use crate::{encode_metadata, EncodedMetadata};
 
 // FIXME(eddyb) maybe include the crate name in this?
 pub const METADATA_FILENAME: &str = "lib.rmeta";
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 90fe52a3438..25ae7b2bc31 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -212,9 +212,11 @@
 //! no means all of the necessary details. Take a look at the rest of
 //! metadata::locator or metadata::creader for all the juicy details!
 
-use crate::creader::{Library, MetadataLoader};
-use crate::errors;
-use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
+use std::borrow::Cow;
+use std::io::{Read, Result as IoResult, Write};
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
+use std::{cmp, fmt};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::memmap::Mmap;
@@ -230,14 +232,12 @@ use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
+use snap::read::FrameDecoder;
 use tracing::{debug, info};
 
-use snap::read::FrameDecoder;
-use std::borrow::Cow;
-use std::io::{Read, Result as IoResult, Write};
-use std::ops::Deref;
-use std::path::{Path, PathBuf};
-use std::{cmp, fmt};
+use crate::creader::{Library, MetadataLoader};
+use crate::errors;
+use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 #[derive(Clone)]
 pub(crate) struct CrateLocator<'a> {
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 1254ebead07..34497f5ac53 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,3 +1,5 @@
+use std::path::PathBuf;
+
 use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
@@ -15,9 +17,7 @@ use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
-use crate::errors;
-
-use std::path::PathBuf;
+use crate::{errors, fluent_generated};
 
 pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
     let formats = if verbatim {
@@ -87,7 +87,6 @@ struct Collector<'tcx> {
 }
 
 impl<'tcx> Collector<'tcx> {
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn process_module(&mut self, module: &ForeignModule) {
         let ForeignModule { def_id, abi, ref foreign_items } = *module;
         let def_id = def_id.expect_local();
@@ -161,7 +160,7 @@ impl<'tcx> Collector<'tcx> {
                                         sess,
                                         sym::link_arg_attribute,
                                         span,
-                                        "link kind `link-arg` is unstable",
+                                        fluent_generated::metadata_link_arg_unstable,
                                     )
                                     .emit();
                                 }
@@ -201,8 +200,13 @@ impl<'tcx> Collector<'tcx> {
                             continue;
                         };
                         if !features.link_cfg {
-                            feature_err(sess, sym::link_cfg, item.span(), "link cfg is unstable")
-                                .emit();
+                            feature_err(
+                                sess,
+                                sym::link_cfg,
+                                item.span(),
+                                fluent_generated::metadata_link_cfg_unstable,
+                            )
+                            .emit();
                         }
                         cfg = Some(link_cfg.clone());
                     }
@@ -266,6 +270,8 @@ impl<'tcx> Collector<'tcx> {
 
                     macro report_unstable_modifier($feature: ident) {
                         if !features.$feature {
+                            // FIXME: make this translatable
+                            #[expect(rustc::untranslatable_diagnostic)]
                             feature_err(
                                 sess,
                                 sym::$feature,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 9874624ae25..8c0ea3eaea9 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1,9 +1,11 @@
 // Decoding metadata from a single crate's metadata
 
-use crate::creader::CStore;
-use crate::rmeta::table::IsDefault;
-use crate::rmeta::*;
+use std::iter::TrustedLen;
+use std::path::Path;
+use std::{io, iter, mem};
 
+pub(super) use cstore_impl::provide;
+use proc_macro::bridge::client::ProcMacro;
 use rustc_ast as ast;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -27,17 +29,14 @@ use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::{Decodable, Decoder};
 use rustc_session::cstore::{CrateSource, ExternCrate};
 use rustc_session::Session;
+use rustc_span::hygiene::HygieneDecodeContext;
 use rustc_span::symbol::kw;
 use rustc_span::{BytePos, Pos, SpanData, SpanDecoder, SyntaxContext, DUMMY_SP};
 use tracing::debug;
 
-use proc_macro::bridge::client::ProcMacro;
-use std::iter::TrustedLen;
-use std::path::Path;
-use std::{io, iter, mem};
-
-pub(super) use cstore_impl::provide;
-use rustc_span::hygiene::HygieneDecodeContext;
+use crate::creader::CStore;
+use crate::rmeta::table::IsDefault;
+use crate::rmeta::*;
 
 mod cstore_impl;
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index bbd9ab5704f..46039f6e5f6 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,8 +1,5 @@
-use crate::creader::{CStore, LoadedMacro};
-use crate::foreign_modules;
-use crate::native_libs;
-use crate::rmeta::table::IsDefault;
-use crate::rmeta::AttrFlags;
+use std::any::Any;
+use std::mem;
 
 use rustc_ast as ast;
 use rustc_attr::Deprecation;
@@ -15,8 +12,7 @@ use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
-use rustc_middle::query::ExternProviders;
-use rustc_middle::query::LocalCrate;
+use rustc_middle::query::{ExternProviders, LocalCrate};
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;
@@ -26,10 +22,11 @@ use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
-use std::any::Any;
-use std::mem;
-
 use super::{Decodable, DecodeContext, DecodeIterator};
+use crate::creader::{CStore, LoadedMacro};
+use crate::rmeta::table::IsDefault;
+use crate::rmeta::AttrFlags;
+use crate::{foreign_modules, native_libs};
 
 trait ProcessQueryValue<'tcx, T> {
     fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T;
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 861bf6b2769..01fbf37788f 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -1,11 +1,11 @@
-use crate::rmeta::DecodeContext;
-use crate::rmeta::EncodeContext;
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
 use rustc_middle::parameterized_over_tcx;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::def_id::{DefIndex, DefPathHash};
 
+use crate::rmeta::{DecodeContext, EncodeContext};
+
 pub(crate) enum DefPathHashMapRef<'tcx> {
     OwnedFromMetadata(odht::HashTable<HashMapConfig, OwnedSlice>),
     BorrowedFromTcx(&'tcx DefPathHashMap),
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 6f31c0fa520..0d83f8c6c5c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,5 +1,8 @@
-use crate::errors::{FailCreateFileEncoder, FailWriteFile};
-use crate::rmeta::*;
+use std::borrow::Borrow;
+use std::collections::hash_map::Entry;
+use std::fs::File;
+use std::io::{Read, Seek, Write};
+use std::path::{Path, PathBuf};
 
 use rustc_ast::Attribute;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -27,13 +30,11 @@ use rustc_span::symbol::sym;
 use rustc_span::{
     ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
 };
-use std::borrow::Borrow;
-use std::collections::hash_map::Entry;
-use std::fs::File;
-use std::io::{Read, Seek, Write};
-use std::path::{Path, PathBuf};
 use tracing::{debug, instrument, trace};
 
+use crate::errors::{FailCreateFileEncoder, FailWriteFile};
+use crate::rmeta::*;
+
 pub(super) struct EncodeContext<'a, 'tcx> {
     opaque: opaque::FileEncoder,
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index e565c8c1ea1..c1b77172983 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,35 +1,35 @@
-use crate::creader::CrateMetadataRef;
+use std::marker::PhantomData;
+use std::num::NonZero;
+
 pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
 use decoder::{DecodeContext, Metadata};
 use def_path_hash_map::DefPathHashMapRef;
 use encoder::EncodeContext;
 pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
-use rustc_ast as ast;
 use rustc_ast::expand::StrippedCfgItem;
-use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
-use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
-use rustc_macros::{MetadataDecodable, MetadataEncodable};
+use rustc_macros::{
+    Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, TyEncodable,
+};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::middle::lib_features::FeatureStability;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
-use rustc_middle::mir;
-use rustc_middle::trivially_parameterized_over_tcx;
 use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams};
-use rustc_middle::ty::{DeducedParamAttrs, ParameterizedOverTcx, TyCtxt};
+use rustc_middle::ty::{
+    self, DeducedParamAttrs, ParameterizedOverTcx, ReprOptions, Ty, TyCtxt, UnusedGenericParams,
+};
 use rustc_middle::util::Providers;
+use rustc_middle::{mir, trivially_parameterized_over_tcx};
 use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
@@ -39,9 +39,10 @@ use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
-use std::marker::PhantomData;
-use std::num::NonZero;
 use table::TableBuilder;
+use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
+
+use crate::creader::CrateMetadataRef;
 
 mod decoder;
 mod def_path_hash_map;
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index dcbddad2dbc..617372a97b5 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -1,9 +1,9 @@
-use crate::rmeta::*;
-
 use rustc_hir::def::CtorOf;
 use rustc_index::Idx;
 use tracing::trace;
 
+use crate::rmeta::*;
+
 pub(super) trait IsDefault: Default {
     fn is_default(&self) -> bool;
 }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 84b47a6ed44..9ebe4a57b02 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -56,18 +56,17 @@
 //!
 //! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
 
-use crate::mir::mono::MonoItem;
-use crate::ty::TyCtxt;
-
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::{HirId, ItemLocalId, OwnerId};
+pub use rustc_query_system::dep_graph::dep_node::DepKind;
 use rustc_query_system::dep_graph::FingerprintStyle;
+pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams};
 use rustc_span::symbol::Symbol;
 
-pub use rustc_query_system::dep_graph::dep_node::DepKind;
-pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams};
+use crate::mir::mono::MonoItem;
+use crate::ty::TyCtxt;
 
 macro_rules! define_dep_nodes {
     (
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index dc0da165af6..b24954584fe 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -1,20 +1,19 @@
-use crate::ty::{self, TyCtxt};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Session;
 
+use crate::ty::{self, TyCtxt};
+
 #[macro_use]
 mod dep_node;
 
-pub use rustc_query_system::dep_graph::debug::EdgeFilter;
-pub use rustc_query_system::dep_graph::{
-    debug::DepNodeFilter, hash_result, DepContext, DepGraphQuery, DepNodeIndex, Deps,
-    SerializedDepGraph, SerializedDepNodeIndex, TaskDepsRef, WorkProduct, WorkProductId,
-    WorkProductMap,
-};
-
 pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt};
 pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
+pub use rustc_query_system::dep_graph::debug::{DepNodeFilter, EdgeFilter};
+pub use rustc_query_system::dep_graph::{
+    hash_result, DepContext, DepGraphQuery, DepNodeIndex, Deps, SerializedDepGraph,
+    SerializedDepNodeIndex, TaskDepsRef, WorkProduct, WorkProductId, WorkProductMap,
+};
 
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>;
 
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 711db4e0a6b..61348cdce23 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -1,7 +1,8 @@
 use std::fmt;
 use std::path::PathBuf;
 
-use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage};
+use rustc_errors::codes::*;
+use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index ad59bfa9047..edab6b5ebde 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,8 +1,3 @@
-use crate::hir::ModuleItems;
-use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
-use crate::query::LocalCrate;
-use crate::ty::TyCtxt;
-use rustc_ast as ast;
 use rustc_ast::visit::{walk_list, VisitorResult};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -13,12 +8,17 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::*;
-use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_target::spec::abi::Abi;
+use {rustc_ast as ast, rustc_hir_pretty as pprust_hir};
+
+use crate::hir::ModuleItems;
+use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
+use crate::query::LocalCrate;
+use crate::ty::TyCtxt;
 
 // FIXME: the structure was necessary in the past but now it
 // only serves as "namespace" for HIR-related methods, and can be
@@ -746,6 +746,10 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option<DefId> {
+        self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id()
+    }
+
     #[inline]
     fn opt_ident(self, id: HirId) -> Option<Ident> {
         match self.tcx.hir_node(id) {
@@ -1161,17 +1165,23 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         }
         Node::ImplItem(ii) => {
             let kind = match ii.kind {
-                ImplItemKind::Const(..) => "assoc const",
-                ImplItemKind::Fn(..) => "method",
-                ImplItemKind::Type(_) => "assoc type",
+                ImplItemKind::Const(..) => "associated constant",
+                ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                    ImplicitSelfKind::None => "associated function",
+                    _ => "method",
+                },
+                ImplItemKind::Type(_) => "associated type",
             };
             format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
         }
         Node::TraitItem(ti) => {
             let kind = match ti.kind {
-                TraitItemKind::Const(..) => "assoc constant",
-                TraitItemKind::Fn(..) => "trait method",
-                TraitItemKind::Type(..) => "assoc type",
+                TraitItemKind::Const(..) => "associated constant",
+                TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                    ImplicitSelfKind::None => "associated function",
+                    _ => "trait method",
+                },
+                TraitItemKind::Type(..) => "associated type",
             };
 
             format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 57c8ba96a20..fa521ab9f2f 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -6,8 +6,6 @@ pub mod map;
 pub mod nested_filter;
 pub mod place;
 
-use crate::query::Providers;
-use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -18,6 +16,9 @@ use rustc_hir::*;
 use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_span::{ErrorGuaranteed, ExpnId};
 
+use crate::query::Providers;
+use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
+
 /// Gather the LocalDefId for each item-like within a module, including items contained within
 /// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
 #[derive(Debug, HashStable, Encodable, Decodable)]
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 1ac35314ead..4c7af0bc372 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -1,10 +1,10 @@
-use crate::ty;
-use crate::ty::Ty;
-
 use rustc_hir::HirId;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 
+use crate::ty;
+use crate::ty::Ty;
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum PlaceBase {
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index 75dc685a16a..bde05210d9f 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -3,15 +3,16 @@
 //! queries come with a lot of machinery for caching and incremental compilation, whereas hooks are
 //! just plain function pointers without any of the query magic.
 
-use crate::mir;
-use crate::query::TyCtxtAt;
-use crate::ty::{Ty, TyCtxt};
 use rustc_hir::def_id::{DefId, DefPathHash};
 use rustc_session::StableCrateId;
 use rustc_span::def_id::{CrateNum, LocalDefId};
 use rustc_span::{ExpnHash, ExpnId, DUMMY_SP};
 use tracing::instrument;
 
+use crate::mir;
+use crate::query::TyCtxtAt;
+use crate::ty::{Ty, TyCtxt};
+
 macro_rules! declare_hooks {
     ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
 
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index dba71d88f40..d4314978819 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -21,18 +21,18 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
+use std::collections::hash_map::Entry;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 pub use rustc_type_ir as ir;
 pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
 use smallvec::SmallVec;
-use std::collections::hash_map::Entry;
 
 use crate::infer::MemberConstraint;
 use crate::mir::ConstraintCategory;
-use crate::ty::GenericArg;
-use crate::ty::{self, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
+use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
 
 pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
 pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs
index f74f71b6b37..19fe9e5a54f 100644
--- a/compiler/rustc_middle/src/infer/mod.rs
+++ b/compiler/rustc_middle/src/infer/mod.rs
@@ -1,12 +1,12 @@
 pub mod canonical;
 pub mod unify_key;
 
-use crate::ty::Region;
-use crate::ty::{OpaqueTypeKey, Ty};
 use rustc_data_structures::sync::Lrc;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
 
+use crate::ty::{OpaqueTypeKey, Region, Ty};
+
 /// Requires that `region` must be equal to one of the regions in `choice_regions`.
 /// We often denote this using the syntax:
 ///
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index a5da7e7739e..3fd4aba3169 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -1,9 +1,11 @@
-use crate::ty::{self, Ty, TyCtxt};
+use std::cmp;
+use std::marker::PhantomData;
+
 use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
-use std::cmp;
-use std::marker::PhantomData;
+
+use crate::ty::{self, Ty, TyCtxt};
 
 pub trait ToType {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index b499604df87..5bd7736a3f3 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -28,6 +28,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(allocator_api)]
@@ -48,7 +49,6 @@
 #![feature(iter_from_coroutine)]
 #![feature(let_chains)]
 #![feature(macro_metavar_expr)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 4e655ca2027..8c27cac1ea8 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -5,10 +5,8 @@ use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::{Diag, MultiSpan};
 use rustc_hir::{HirId, ItemLocalId};
 use rustc_macros::HashStable;
-use rustc_session::lint::{
-    builtin::{self, FORBIDDEN_LINT_GROUPS},
-    FutureIncompatibilityReason, Level, Lint, LintId,
-};
+use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
+use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintId};
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::{symbol, DesugaringKind, Span, Symbol, DUMMY_SP};
@@ -230,9 +228,11 @@ pub fn explain_lint_level_source(
                 err.note_once(format!(
                     "`{flag} {hyphen_case_lint_name}` implied by `{flag} {hyphen_case_flag_val}`"
                 ));
-                err.help_once(format!(
-                    "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`"
-                ));
+                if matches!(orig_level, Level::Warn | Level::Deny) {
+                    err.help_once(format!(
+                        "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`"
+                    ));
+                }
             }
         }
         LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => {
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
index 589f274eb17..c3175c6bdf5 100644
--- a/compiler/rustc_middle/src/metadata.rs
+++ b/compiler/rustc_middle/src/metadata.rs
@@ -1,11 +1,11 @@
-use crate::ty;
-
 use rustc_hir::def::Res;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::Ident;
 use smallvec::SmallVec;
 
+use crate::ty;
+
 /// A simplified version of `ImportKind` from resolve.
 /// `DefId`s here correspond to `use` and `extern crate` items themselves, not their targets.
 #[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 3ddf889b63a..b7d290e58d2 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,10 +1,11 @@
-use crate::mir::mono::Linkage;
 use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::Align;
 use rustc_target::spec::SanitizerSet;
 
+use crate::mir::mono::Linkage;
+
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
 pub struct CodegenFnAttrs {
     pub flags: CodegenFnAttrFlags,
@@ -27,7 +28,7 @@ pub struct CodegenFnAttrs {
     pub link_ordinal: Option<u16>,
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
-    pub target_features: Vec<Symbol>,
+    pub target_features: Vec<TargetFeature>,
     /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
     pub linkage: Option<Linkage>,
     /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -51,6 +52,15 @@ pub struct CodegenFnAttrs {
 }
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct TargetFeature {
+    /// The name of the target feature (e.g. "avx")
+    pub name: Symbol,
+    /// The feature is implied by another feature, rather than explicitly added by the
+    /// `#[target_feature]` attribute
+    pub implied: bool,
+}
+
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct PatchableFunctionEntry {
     /// Nops to prepend to the function
     prefix: u8,
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
index 74a5dfb0400..615a7402139 100644
--- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -1,6 +1,7 @@
+use std::path::PathBuf;
+
 use rustc_data_structures::sync::Lrc;
 use rustc_macros::{Decodable, Encodable, HashStable};
-use std::path::PathBuf;
 
 #[derive(HashStable)]
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
index b35cc83cb8e..0bfbd398797 100644
--- a/compiler/rustc_middle/src/middle/exported_symbols.rs
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -1,8 +1,8 @@
-use crate::ty::GenericArgsRef;
-use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable};
 
+use crate::ty::{self, GenericArgsRef, Ty, TyCtxt};
+
 /// The SymbolExportLevel of a symbols specifies from which kinds of crates
 /// the symbol will be exported. `C` symbols will be exported from any
 /// kind of crate, including cdylibs which export very few things.
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index a0c9af436e2..f141af44900 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -7,13 +7,13 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
-use crate::ty::{self, TyCtxt};
-
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_span::Span;
 use rustc_target::spec::PanicStrategy;
 
+use crate::ty::{self, TyCtxt};
+
 impl<'tcx> TyCtxt<'tcx> {
     /// Returns the `DefId` for a given `LangItem`.
     /// If not found, fatally aborts compilation.
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index d0b4f36a426..70810f51a1f 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -8,14 +8,14 @@
 //! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
 //! just peeks and looks for that attribute.
 
-use crate::error::LimitInvalid;
-use crate::query::Providers;
+use std::num::IntErrorKind;
+
 use rustc_ast::Attribute;
-use rustc_session::Session;
-use rustc_session::{Limit, Limits};
+use rustc_session::{Limit, Limits, Session};
 use rustc_span::symbol::{sym, Symbol};
 
-use std::num::IntErrorKind;
+use crate::error::LimitInvalid;
+use crate::query::Providers;
 
 pub fn provide(providers: &mut Providers) {
     providers.limits = |tcx, ()| Limits {
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index 5c395afadd7..0c4f37ab14f 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -6,7 +6,8 @@ pub mod lang_items;
 pub mod lib_features {
     use rustc_data_structures::unord::UnordMap;
     use rustc_macros::{HashStable, TyDecodable, TyEncodable};
-    use rustc_span::{symbol::Symbol, Span};
+    use rustc_span::symbol::Symbol;
+    use rustc_span::Span;
 
     #[derive(Copy, Clone, Debug, PartialEq, Eq)]
     #[derive(HashStable, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 4b47b019fd4..db70f53b7b4 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -2,14 +2,16 @@
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
 
-use crate::ty::{TyCtxt, Visibility};
+use std::hash::Hash;
+
 use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def::DefKind;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID};
-use std::hash::Hash;
+
+use crate::ty::{TyCtxt, Visibility};
 
 /// Represents the levels of effective visibility an item can have.
 ///
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 6e89dc494fa..6ef1801717c 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -6,7 +6,9 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
-use crate::ty::TyCtxt;
+use std::fmt;
+use std::ops::Deref;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir as hir;
@@ -15,8 +17,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::{Span, DUMMY_SP};
 use tracing::debug;
 
-use std::fmt;
-use std::ops::Deref;
+use crate::ty::TyCtxt;
 
 /// Represents a statically-describable scope that can be used to
 /// bound the lifetime/region for values.
diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
index d0103f62231..a4f6d7afe4d 100644
--- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
+++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
@@ -1,13 +1,13 @@
 //! Name resolution for lifetimes and late-bound type and const variables: type declarations.
 
-use crate::ty;
-
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{ItemLocalId, OwnerId};
 use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable};
 
+use crate::ty;
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum ResolvedArg {
     StaticLifetime,
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index b113e81bd2d..3b8861378e0 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -1,9 +1,8 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-pub use self::StabilityLevel::*;
+use std::num::NonZero;
 
-use crate::ty::{self, TyCtxt};
 use rustc_ast::NodeId;
 use rustc_attr::{
     self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
@@ -22,9 +21,11 @@ use rustc_session::parse::feature_err_issue;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use std::num::NonZero;
 use tracing::debug;
 
+pub use self::StabilityLevel::*;
+use crate::ty::{self, TyCtxt};
+
 #[derive(PartialEq, Clone, Copy, Debug)]
 pub enum StabilityLevel {
     Unstable,
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index f9398b254c7..c08bfc1fa95 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -1,6 +1,3 @@
-use crate::mir::traversal::Postorder;
-use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK};
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph;
 use rustc_data_structures::graph::dominators::{dominators, Dominators};
@@ -11,6 +8,9 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use smallvec::SmallVec;
 
+use crate::mir::traversal::Postorder;
+use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK};
+
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct BasicBlocks<'tcx> {
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 89f5acacf9d..563647ad4e6 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -2,16 +2,15 @@ use std::fmt::{self, Debug, Display, Formatter};
 
 use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+use rustc_session::config::RemapPathScopeComponents;
+use rustc_session::RemapFileNameExt;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{HasDataLayout, Size};
 
 use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar};
 use crate::mir::{pretty_print_const_value, Promoted};
-use crate::ty::print::with_no_trimmed_paths;
-use crate::ty::GenericArgsRef;
-use crate::ty::ScalarInt;
-use crate::ty::{self, print::pretty_print_const, Ty, TyCtxt};
+use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
+use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt};
 
 ///////////////////////////////////////////////////////////////////////////
 /// Evaluated Constants
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 2a593340849..b11c523cfe9 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -1,11 +1,11 @@
 //! Metadata from source code coverage analysis and instrumentation.
 
+use std::fmt::{self, Debug, Formatter};
+
 use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_span::{Span, Symbol};
 
-use std::fmt::{self, Debug, Formatter};
-
 rustc_index::newtype_index! {
     /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR
     /// lowering, so that those blocks can be identified later.
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
index 809d4cdce8d..e1c3d8156d8 100644
--- a/compiler/rustc_middle/src/mir/generic_graphviz.rs
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -1,7 +1,8 @@
+use std::io::{self, Write};
+
 use rustc_data_structures::graph::{self, iterate};
 use rustc_graphviz as dot;
 use rustc_middle::ty::TyCtxt;
-use std::io::{self, Write};
 
 pub struct GraphvizWriter<
     'a,
diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
index 2eadc4d553c..a3fe8f9cffa 100644
--- a/compiler/rustc_middle/src/mir/graphviz.rs
+++ b/compiler/rustc_middle/src/mir/graphviz.rs
@@ -1,7 +1,8 @@
+use std::io::{self, Write};
+
 use gsgdt::GraphvizSettings;
 use rustc_graphviz as dot;
 use rustc_middle::mir::*;
-use std::io::{self, Write};
 
 use super::generic_graph::mir_fn_to_generic_graph;
 use super::pretty::dump_mir_def_ids;
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index cac3bf948a0..665ab2797f2 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -4,14 +4,14 @@ mod init_mask;
 mod provenance_map;
 
 use std::borrow::Cow;
-use std::fmt;
-use std::hash;
 use std::hash::Hash;
 use std::ops::{Deref, DerefMut, Range};
-use std::ptr;
+use std::{fmt, hash, ptr};
 
 use either::{Left, Right};
-
+use init_mask::*;
+pub use init_mask::{InitChunk, InitChunkIter};
+use provenance_map::*;
 use rustc_ast::Mutability;
 use rustc_data_structures::intern::Interned;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
@@ -23,10 +23,6 @@ use super::{
     ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo,
 };
 use crate::ty;
-use init_mask::*;
-use provenance_map::*;
-
-pub use init_mask::{InitChunk, InitChunkIter};
 
 /// Functionality required for the bytes of an `Allocation`.
 pub trait AllocBytes: Clone + fmt::Debug + Deref<Target = [u8]> + DerefMut<Target = [u8]> {
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
index d60db775ff0..1d2a82c575a 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
@@ -1,9 +1,8 @@
 #[cfg(test)]
 mod tests;
 
-use std::hash;
-use std::iter;
 use std::ops::Range;
+use std::{hash, iter};
 
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_serialize::{Decodable, Encodable};
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index 4e37295a571..4fe219441a0 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -3,13 +3,14 @@
 
 use std::cmp;
 
-use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_macros::HashStable;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_target::abi::{HasDataLayout, Size};
 use tracing::trace;
 
+use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance};
+
 /// Stores the provenance information of pointers stored in memory.
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(HashStable)]
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 9df19565ab3..69ce3e08735 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,19 +1,19 @@
+use std::any::Any;
+use std::backtrace::Backtrace;
 use std::borrow::Cow;
-use std::{any::Any, backtrace::Backtrace, fmt};
+use std::fmt;
 
 use either::Either;
-
 use rustc_ast_ir::Mutability;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_session::CtfeBacktrace;
-use rustc_span::Symbol;
-use rustc_span::{def_id::DefId, Span, DUMMY_SP};
+use rustc_span::def_id::DefId;
+use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
 
 use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar};
-
 use crate::error;
 use crate::mir::{ConstAlloc, ConstValue};
 use crate::ty::{self, layout, tls, Ty, TyCtxt, ValTree};
@@ -329,16 +329,22 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Using a pointer after it got freed.
     PointerUseAfterFree(AllocId, CheckInAllocMsg),
     /// Used a pointer outside the bounds it is valid for.
-    /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
     PointerOutOfBounds {
         alloc_id: AllocId,
         alloc_size: Size,
         ptr_offset: i64,
-        ptr_size: Size,
+        /// The size of the memory range that was expected to be in-bounds.
+        inbounds_size: i64,
         msg: CheckInAllocMsg,
     },
     /// Using an integer as a pointer in the wrong way.
-    DanglingIntPointer(u64, CheckInAllocMsg),
+    DanglingIntPointer {
+        addr: u64,
+        /// The size of the memory range that was expected to be in-bounds (or 0 if we need an
+        /// allocation but not any actual memory there, e.g. for function pointers).
+        inbounds_size: i64,
+        msg: CheckInAllocMsg,
+    },
     /// Used a pointer with bad alignment.
     AlignmentCheckFailed(Misalignment, CheckAlignMsg),
     /// Writing to read-only memory.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 15febfa7d9c..91e71c12cae 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -8,15 +8,11 @@ mod pointer;
 mod queries;
 mod value;
 
-use std::fmt;
-use std::io;
 use std::io::{Read, Write};
 use std::num::NonZero;
-
-use tracing::{debug, trace};
+use std::{fmt, io};
 
 use rustc_ast::LitKind;
-use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::ErrorGuaranteed;
@@ -25,20 +21,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_serialize::{Decodable, Encodable};
 use rustc_target::abi::{AddressSpace, Endian, HasDataLayout};
-
-use crate::mir;
-use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::GenericArgKind;
-use crate::ty::{self, Instance, Ty, TyCtxt};
-
-pub use self::error::{
-    BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
-    EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
-    InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo,
-    MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
-    ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
-    ValidationErrorKind,
-};
+use tracing::{debug, trace};
 // Also make the error macros available from this module.
 pub use {
     err_exhaust, err_inval, err_machine_stop, err_ub, err_ub_custom, err_ub_format, err_unsup,
@@ -46,14 +29,23 @@ pub use {
     throw_ub_format, throw_unsup, throw_unsup_format,
 };
 
-pub use self::value::Scalar;
-
 pub use self::allocation::{
     alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation,
     InitChunk, InitChunkIter,
 };
-
+pub use self::error::{
+    BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
+    EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
+    InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo,
+    MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
+    ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
+    ValidationErrorKind,
+};
 pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
+pub use self::value::Scalar;
+use crate::mir;
+use crate::ty::codec::{TyDecoder, TyEncoder};
+use crate::ty::{self, Instance, Ty, TyCtxt};
 
 /// Uniquely identifies one of the following:
 /// - A constant
@@ -133,11 +125,10 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
             AllocDiscriminant::Alloc.encode(encoder);
             alloc.encode(encoder);
         }
-        GlobalAlloc::Function { instance, unique } => {
+        GlobalAlloc::Function { instance } => {
             trace!("encoding {:?} with {:#?}", alloc_id, instance);
             AllocDiscriminant::Fn.encode(encoder);
             instance.encode(encoder);
-            unique.encode(encoder);
         }
         GlobalAlloc::VTable(ty, poly_trait_ref) => {
             trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
@@ -226,38 +217,32 @@ impl<'s> AllocDecodingSession<'s> {
         }
 
         // Now decode the actual data.
-        let alloc_id = decoder.with_position(pos, |decoder| {
-            match alloc_kind {
-                AllocDiscriminant::Alloc => {
-                    trace!("creating memory alloc ID");
-                    let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
-                    trace!("decoded alloc {:?}", alloc);
-                    decoder.interner().reserve_and_set_memory_alloc(alloc)
-                }
-                AllocDiscriminant::Fn => {
-                    trace!("creating fn alloc ID");
-                    let instance = ty::Instance::decode(decoder);
-                    trace!("decoded fn alloc instance: {:?}", instance);
-                    let unique = bool::decode(decoder);
-                    // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which
-                    // is not possible in this context. That's why the allocation stores
-                    // whether it is unique or not.
-                    decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique)
-                }
-                AllocDiscriminant::VTable => {
-                    trace!("creating vtable alloc ID");
-                    let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
-                    let poly_trait_ref =
-                        <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
-                    trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
-                    decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref)
-                }
-                AllocDiscriminant::Static => {
-                    trace!("creating extern static alloc ID");
-                    let did = <DefId as Decodable<D>>::decode(decoder);
-                    trace!("decoded static def-ID: {:?}", did);
-                    decoder.interner().reserve_and_set_static_alloc(did)
-                }
+        let alloc_id = decoder.with_position(pos, |decoder| match alloc_kind {
+            AllocDiscriminant::Alloc => {
+                trace!("creating memory alloc ID");
+                let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
+                trace!("decoded alloc {:?}", alloc);
+                decoder.interner().reserve_and_set_memory_alloc(alloc)
+            }
+            AllocDiscriminant::Fn => {
+                trace!("creating fn alloc ID");
+                let instance = ty::Instance::decode(decoder);
+                trace!("decoded fn alloc instance: {:?}", instance);
+                decoder.interner().reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT)
+            }
+            AllocDiscriminant::VTable => {
+                trace!("creating vtable alloc ID");
+                let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
+                let poly_trait_ref =
+                    <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
+                trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
+                decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT)
+            }
+            AllocDiscriminant::Static => {
+                trace!("creating extern static alloc ID");
+                let did = <DefId as Decodable<D>>::decode(decoder);
+                trace!("decoded static def-ID: {:?}", did);
+                decoder.interner().reserve_and_set_static_alloc(did)
             }
         });
 
@@ -272,12 +257,7 @@ impl<'s> AllocDecodingSession<'s> {
 #[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub enum GlobalAlloc<'tcx> {
     /// The alloc ID is used as a function pointer.
-    Function {
-        instance: Instance<'tcx>,
-        /// Stores whether this instance is unique, i.e. all pointers to this function use the same
-        /// alloc ID.
-        unique: bool,
-    },
+    Function { instance: Instance<'tcx> },
     /// This alloc ID points to a symbolic (not-reified) vtable.
     VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
     /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -330,14 +310,17 @@ impl<'tcx> GlobalAlloc<'tcx> {
     }
 }
 
+pub const CTFE_ALLOC_SALT: usize = 0;
+
 pub(crate) struct AllocMap<'tcx> {
     /// Maps `AllocId`s to their corresponding allocations.
     alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
 
-    /// Used to ensure that statics and functions only get one associated `AllocId`.
-    //
-    // FIXME: Should we just have two separate dedup maps for statics and functions each?
-    dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
+    /// Used to deduplicate global allocations: functions, vtables, string literals, ...
+    ///
+    /// The `usize` is a "salt" used by Miri to make deduplication imperfect, thus better emulating
+    /// the actual guarantees.
+    dedup: FxHashMap<(GlobalAlloc<'tcx>, usize), AllocId>,
 
     /// The `AllocId` to assign to the next requested ID.
     /// Always incremented; never gets smaller.
@@ -375,74 +358,40 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
     /// Should not be used for mutable memory.
-    fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
+    fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>, salt: usize) -> AllocId {
         let mut alloc_map = self.alloc_map.lock();
         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) {
+        let alloc_salt = (alloc, salt);
+        if let Some(&alloc_id) = alloc_map.dedup.get(&alloc_salt) {
             return alloc_id;
         }
         let id = alloc_map.reserve();
-        debug!("creating alloc {alloc:?} with id {id:?}");
-        alloc_map.alloc_map.insert(id, alloc.clone());
-        alloc_map.dedup.insert(alloc, id);
+        debug!("creating alloc {:?} with id {id:?}", alloc_salt.0);
+        alloc_map.alloc_map.insert(id, alloc_salt.0.clone());
+        alloc_map.dedup.insert(alloc_salt, id);
         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))
+    pub fn reserve_and_set_memory_dedup(self, mem: ConstAllocation<'tcx>, salt: usize) -> AllocId {
+        self.reserve_and_set_dedup(GlobalAlloc::Memory(mem), salt)
     }
 
     /// 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 {
-        self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
-    }
-
-    /// Generates an `AllocId` for a function. The caller must already have decided whether this
-    /// function obtains a unique AllocId or gets de-duplicated via the cache.
-    fn reserve_and_set_fn_alloc_internal(self, instance: Instance<'tcx>, unique: bool) -> AllocId {
-        let alloc = GlobalAlloc::Function { instance, unique };
-        if unique {
-            // Deduplicate.
-            self.reserve_and_set_dedup(alloc)
-        } else {
-            // Get a fresh ID.
-            let mut alloc_map = self.alloc_map.lock();
-            let id = alloc_map.reserve();
-            alloc_map.alloc_map.insert(id, alloc);
-            id
-        }
+        let salt = 0; // Statics have a guaranteed unique address, no salt added.
+        self.reserve_and_set_dedup(GlobalAlloc::Static(static_id), salt)
     }
 
-    /// Generates an `AllocId` for a function. Depending on the function type,
-    /// this might get deduplicated or assigned a new ID each time.
-    pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
-        // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
-        // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
-        // duplicated across crates. We thus generate a new `AllocId` for every mention of a
-        // function. This means that `main as fn() == main as fn()` is false, while `let x = main as
-        // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify
-        // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will
-        // actually emit duplicate functions. It does that when they have non-lifetime generics, or
-        // when they can be inlined. All other functions are given a unique address.
-        // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied
-        // upon for anything. But if we don't do this, backtraces look terrible.
-        let is_generic = instance
-            .args
-            .into_iter()
-            .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
-        let can_be_inlined = match self.codegen_fn_attrs(instance.def_id()).inline {
-            InlineAttr::Never => false,
-            _ => true,
-        };
-        let unique = !is_generic && !can_be_inlined;
-        self.reserve_and_set_fn_alloc_internal(instance, unique)
+    /// Generates an `AllocId` for a function. Will get deduplicated.
+    pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>, salt: usize) -> AllocId {
+        self.reserve_and_set_dedup(GlobalAlloc::Function { instance }, salt)
     }
 
     /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
@@ -450,8 +399,9 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         ty: Ty<'tcx>,
         poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        salt: usize,
     ) -> AllocId {
-        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref))
+        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref), salt)
     }
 
     /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index a0acacc844f..6cfd07d699c 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -1,10 +1,11 @@
-use super::{AllocId, InterpResult};
+use std::fmt;
+use std::num::NonZero;
 
 use rustc_data_structures::static_assert_size;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_target::abi::{HasDataLayout, Size};
 
-use std::{fmt, num::NonZero};
+use super::AllocId;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Pointer arithmetic
@@ -39,62 +40,13 @@ pub trait PointerArithmetic: HasDataLayout {
     }
 
     #[inline]
-    fn target_usize_to_isize(&self, val: u64) -> i64 {
-        let val = val as i64;
-        // Now wrap-around into the machine_isize range.
-        if val > self.target_isize_max() {
-            // This can only happen if the ptr size is < 64, so we know max_usize_plus_1 fits into
-            // i64.
-            debug_assert!(self.pointer_size().bits() < 64);
-            let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
-            val - i64::try_from(max_usize_plus_1).unwrap()
-        } else {
-            val
-        }
-    }
-
-    /// Helper function: truncate given value-"overflowed flag" pair to pointer size and
-    /// update "overflowed flag" if there was an overflow.
-    /// This should be called by all the other methods before returning!
-    #[inline]
-    fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) {
-        let val = u128::from(val);
-        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
-        (u64::try_from(val % max_ptr_plus_1).unwrap(), over || val >= max_ptr_plus_1)
-    }
-
-    #[inline]
-    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
-        // We do not need to check if i fits in a machine usize. If it doesn't,
-        // either the wrapping_add will wrap or res will not fit in a pointer.
-        let res = val.overflowing_add(i);
-        self.truncate_to_ptr(res)
-    }
-
-    #[inline]
-    fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
-        // We need to make sure that i fits in a machine isize.
-        let n = i.unsigned_abs();
-        if i >= 0 {
-            let (val, over) = self.overflowing_offset(val, n);
-            (val, over || i > self.target_isize_max())
-        } else {
-            let res = val.overflowing_sub(n);
-            let (val, over) = self.truncate_to_ptr(res);
-            (val, over || i < self.target_isize_min())
-        }
-    }
-
-    #[inline]
-    fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
-        let (res, over) = self.overflowing_offset(val, i);
-        if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
+    fn truncate_to_target_usize(&self, val: u64) -> u64 {
+        self.pointer_size().truncate(val.into()).try_into().unwrap()
     }
 
     #[inline]
-    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
-        let (res, over) = self.overflowing_signed_offset(val, i);
-        if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
+    fn sign_extend_to_target_isize(&self, val: u64) -> i64 {
+        self.pointer_size().sign_extend(val.into()).try_into().unwrap()
     }
 }
 
@@ -330,7 +282,7 @@ impl<Prov> Pointer<Option<Prov>> {
     }
 }
 
-impl<'tcx, Prov> Pointer<Prov> {
+impl<Prov> Pointer<Prov> {
     #[inline(always)]
     pub fn new(provenance: Prov, offset: Size) -> Self {
         Pointer { provenance, offset }
@@ -348,43 +300,16 @@ impl<'tcx, Prov> Pointer<Prov> {
         Pointer { provenance: f(self.provenance), ..self }
     }
 
-    #[inline]
-    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
-        Ok(Pointer {
-            offset: Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
-            ..self
-        })
-    }
-
-    #[inline]
-    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
-        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
-        let ptr = Pointer { offset: Size::from_bytes(res), ..self };
-        (ptr, over)
-    }
-
     #[inline(always)]
     pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
-        self.overflowing_offset(i, cx).0
-    }
-
-    #[inline]
-    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
-        Ok(Pointer {
-            offset: Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
-            ..self
-        })
-    }
-
-    #[inline]
-    pub fn overflowing_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> (Self, bool) {
-        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
-        let ptr = Pointer { offset: Size::from_bytes(res), ..self };
-        (ptr, over)
+        let res =
+            cx.data_layout().truncate_to_target_usize(self.offset.bytes().wrapping_add(i.bytes()));
+        Pointer { offset: Size::from_bytes(res), ..self }
     }
 
     #[inline(always)]
     pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
-        self.overflowing_signed_offset(i, cx).0
+        // It's wrapping anyway, so we can just cast to `u64`.
+        self.wrapping_offset(Size::from_bytes(i as u64), cx)
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 96613592bbc..675e78603ae 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -1,17 +1,16 @@
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_session::lint;
+use rustc_span::{Span, DUMMY_SP};
+use tracing::{debug, instrument};
+
 use super::{
     ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
 };
-
 use crate::mir;
 use crate::query::TyCtxtEnsure;
 use crate::ty::visit::TypeVisitableExt;
-use crate::ty::GenericArgs;
-use crate::ty::{self, TyCtxt};
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
-use rustc_session::lint;
-use rustc_span::{Span, DUMMY_SP};
-use tracing::{debug, instrument};
+use crate::ty::{self, GenericArgs, TyCtxt};
 
 impl<'tcx> TyCtxt<'tcx> {
     /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index a84a4c583ed..84c17b39a62 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -1,20 +1,16 @@
 use std::fmt;
 
 use either::{Either, Left, Right};
-
-use rustc_apfloat::{
-    ieee::{Double, Half, Quad, Single},
-    Float,
-};
+use rustc_apfloat::ieee::{Double, Half, Quad, Single};
+use rustc_apfloat::Float;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_target::abi::{HasDataLayout, Size};
 
-use crate::ty::ScalarInt;
-
 use super::{
     AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance,
     ScalarSizeMismatch,
 };
+use crate::ty::ScalarInt;
 
 /// A `Scalar` represents an immediate, primitive value existing outside of a
 /// `memory::Allocation`. It is in many ways like a small chunk of an `Allocation`, up to 16 bytes in
@@ -397,7 +393,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     #[inline]
     pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> {
         let b = self.to_bits(size)?;
-        Ok(size.sign_extend(b) as i128)
+        Ok(size.sign_extend(b))
     }
 
     /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 83e3898cebf..46c4d586f6a 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2,53 +2,49 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
-use crate::mir::interpret::{AllocRange, Scalar};
-use crate::mir::visit::MirVisitable;
-use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
-use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
-use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::visit::TypeVisitableExt;
-use crate::ty::{self, List, Ty, TyCtxt};
-use crate::ty::{AdtDef, Instance, InstanceKind, UserTypeAnnotationIndex};
-use crate::ty::{GenericArg, GenericArgsRef};
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+use std::fmt::{self, Debug, Formatter};
+use std::ops::{Index, IndexMut};
+use std::{iter, mem};
 
+pub use basic_blocks::BasicBlocks;
+use either::Either;
+use polonius_engine::Atom;
+pub use rustc_ast::Mutability;
 use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::graph::dominators::Dominators;
 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::{
     self as hir, BindingMode, ByRef, CoroutineDesugaring, CoroutineKind, HirId, ImplicitSelfKind,
 };
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_session::Session;
-use rustc_span::source_map::Spanned;
-use rustc_target::abi::{FieldIdx, VariantIdx};
-
-use polonius_engine::Atom;
-pub use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_serialize::{Decodable, Encodable};
+use rustc_session::Session;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
-
-use either::Either;
+use rustc_target::abi::{FieldIdx, VariantIdx};
 use tracing::trace;
 
-use std::borrow::Cow;
-use std::cell::RefCell;
-use std::collections::hash_map::Entry;
-use std::fmt::{self, Debug, Formatter};
-use std::ops::{Index, IndexMut};
-use std::{iter, mem};
-
 pub use self::query::*;
 use self::visit::TyContext;
-pub use basic_blocks::BasicBlocks;
+use crate::mir::interpret::{AllocRange, Scalar};
+use crate::mir::visit::MirVisitable;
+use crate::ty::codec::{TyDecoder, TyEncoder};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::ty::print::{pretty_print_const, with_no_trimmed_paths, FmtPrinter, Printer};
+use crate::ty::visit::TypeVisitableExt;
+use crate::ty::{
+    self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt,
+    UserTypeAnnotationIndex,
+};
 
 mod basic_blocks;
 mod consts;
@@ -70,17 +66,18 @@ pub mod traversal;
 mod type_foldable;
 pub mod visit;
 
-pub use self::generic_graph::graphviz_safe_def_name;
-pub use self::graphviz::write_mir_graphviz;
-pub use self::pretty::{
-    create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere,
-};
 pub use consts::*;
 use pretty::pretty_print_const_value;
 pub use statement::*;
 pub use syntax::*;
 pub use terminator::*;
 
+pub use self::generic_graph::graphviz_safe_def_name;
+pub use self::graphviz::write_mir_graphviz;
+pub use self::pretty::{
+    create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere,
+};
+
 /// Types for locals
 pub type LocalDecls<'tcx> = IndexSlice<Local, LocalDecl<'tcx>>;
 
@@ -386,15 +383,17 @@ pub struct Body<'tcx> {
 
     /// Constants that are required to evaluate successfully for this MIR to be well-formed.
     /// We hold in this field all the constants we are not able to evaluate yet.
+    /// `None` indicates that the list has not been computed yet.
     ///
     /// This is soundness-critical, we make a guarantee that all consts syntactically mentioned in a
     /// function have successfully evaluated if the function ever gets executed at runtime.
-    pub required_consts: Vec<ConstOperand<'tcx>>,
+    pub required_consts: Option<Vec<ConstOperand<'tcx>>>,
 
     /// Further items that were mentioned in this function and hence *may* become monomorphized,
     /// depending on optimizations. We use this to avoid optimization-dependent compile errors: the
     /// collector recursively traverses all "mentioned" items and evaluates all their
     /// `required_consts`.
+    /// `None` indicates that the list has not been computed yet.
     ///
     /// This is *not* soundness-critical and the contents of this list are *not* a stable guarantee.
     /// All that's relevant is that this set is optimization-level-independent, and that it includes
@@ -402,7 +401,7 @@ pub struct Body<'tcx> {
     /// set after drop elaboration, so some drop calls that can never be reached are not considered
     /// "mentioned".) See the documentation of `CollectionMode` in
     /// `compiler/rustc_monomorphize/src/collector.rs` for more context.
-    pub mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>,
+    pub mentioned_items: Option<Vec<Spanned<MentionedItem<'tcx>>>>,
 
     /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
     ///
@@ -480,8 +479,8 @@ impl<'tcx> Body<'tcx> {
             spread_arg: None,
             var_debug_info,
             span,
-            required_consts: Vec::new(),
-            mentioned_items: Vec::new(),
+            required_consts: None,
+            mentioned_items: None,
             is_polymorphic: false,
             injection_phase: None,
             tainted_by_errors,
@@ -510,8 +509,8 @@ impl<'tcx> Body<'tcx> {
             arg_count: 0,
             spread_arg: None,
             span: DUMMY_SP,
-            required_consts: Vec::new(),
-            mentioned_items: Vec::new(),
+            required_consts: None,
+            mentioned_items: None,
             var_debug_info: Vec::new(),
             is_polymorphic: false,
             injection_phase: None,
@@ -788,6 +787,40 @@ impl<'tcx> Body<'tcx> {
         // No inlined `SourceScope`s, or all of them were `#[track_caller]`.
         caller_location.unwrap_or_else(|| from_span(source_info.span))
     }
+
+    #[track_caller]
+    pub fn set_required_consts(&mut self, required_consts: Vec<ConstOperand<'tcx>>) {
+        assert!(
+            self.required_consts.is_none(),
+            "required_consts for {:?} have already been set",
+            self.source.def_id()
+        );
+        self.required_consts = Some(required_consts);
+    }
+    #[track_caller]
+    pub fn required_consts(&self) -> &[ConstOperand<'tcx>] {
+        match &self.required_consts {
+            Some(l) => l,
+            None => panic!("required_consts for {:?} have not yet been set", self.source.def_id()),
+        }
+    }
+
+    #[track_caller]
+    pub fn set_mentioned_items(&mut self, mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>) {
+        assert!(
+            self.mentioned_items.is_none(),
+            "mentioned_items for {:?} have already been set",
+            self.source.def_id()
+        );
+        self.mentioned_items = Some(mentioned_items);
+    }
+    #[track_caller]
+    pub fn mentioned_items(&self) -> &[Spanned<MentionedItem<'tcx>>] {
+        match &self.mentioned_items {
+            Some(l) => l,
+            None => panic!("mentioned_items for {:?} have not yet been set", self.source.def_id()),
+        }
+    }
 }
 
 impl<'tcx> Index<BasicBlock> for Body<'tcx> {
@@ -1815,8 +1848,9 @@ impl DefLocation {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(BasicBlockData<'_>, 128);
     static_assert_size!(LocalDecl<'_>, 40);
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 146cd6dfbeb..336a9388a56 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,9 +1,8 @@
-use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
-use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt};
+use std::fmt;
+use std::hash::Hash;
+
 use rustc_attr::InlineAttr;
-use rustc_data_structures::base_n::BaseNString;
-use rustc_data_structures::base_n::ToBaseN;
-use rustc_data_structures::base_n::CASE_INSENSITIVE;
+use rustc_data_structures::base_n::{BaseNString, ToBaseN, CASE_INSENSITIVE};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey};
@@ -16,10 +15,11 @@ use rustc_query_system::ich::StableHashingContext;
 use rustc_session::config::OptLevel;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
-use std::fmt;
-use std::hash::Hash;
 use tracing::debug;
 
+use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
+use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt};
+
 /// Describes how a monomorphization will be instantiated in object files.
 #[derive(PartialEq)]
 pub enum InstantiationMode {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 223249952dc..f2d87814130 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -4,9 +4,6 @@ use std::fs;
 use std::io::{self, Write as _};
 use std::path::{Path, PathBuf};
 
-use crate::mir::interpret::ConstAllocation;
-
-use super::graphviz::write_mir_fn_graphviz;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir::interpret::{
     alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer,
@@ -17,6 +14,9 @@ use rustc_middle::mir::*;
 use rustc_target::abi::Size;
 use tracing::trace;
 
+use super::graphviz::write_mir_fn_graphviz;
+use crate::mir::interpret::ConstAllocation;
+
 const INDENT: &str = "    ";
 /// Alignment for lining up comments following MIR statements
 pub(crate) const ALIGN: usize = 40;
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index acf4414c4d6..a36e49f6ee0 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,7 +1,8 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir;
-use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt};
+use std::cell::Cell;
+use std::fmt::{self, Debug};
+
 use derive_where::derive_where;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
@@ -13,10 +14,10 @@ use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use smallvec::SmallVec;
-use std::cell::Cell;
-use std::fmt::{self, Debug};
 
 use super::{ConstValue, SourceInfo};
+use crate::mir;
+use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt};
 
 rustc_index::newtype_index! {
     #[derive(HashStable)]
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index ac3feb71a2b..3009ca8d809 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -1,6 +1,7 @@
 //! Functionality for statements, operands, places, and things that appear in them.
 
-use super::{interpret::GlobalAlloc, *};
+use super::interpret::GlobalAlloc;
+use super::*;
 
 ///////////////////////////////////////////////////////////////////////////
 // Statements
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 620fa962d79..1119ff6ff3d 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -3,31 +3,26 @@
 //! This is in a dedicated file so that changes to this file can be reviewed more carefully.
 //! The intention is that this file only contains datatype declarations, no code.
 
-use super::{BasicBlock, Const, Local, UserTypeProjection};
-
-use crate::mir::coverage::CoverageKind;
-use crate::traits::Reveal;
-use crate::ty::adjustment::PointerCoercion;
-use crate::ty::GenericArgsRef;
-use crate::ty::{self, List, Ty};
-use crate::ty::{Region, UserTypeAnnotationIndex};
-
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability};
 use rustc_data_structures::packed::Pu128;
 use rustc_hir::def_id::DefId;
 use rustc_hir::CoroutineKind;
 use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_span::source_map::Spanned;
-use rustc_target::abi::{FieldIdx, VariantIdx};
-
-use rustc_ast::Mutability;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
+use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use smallvec::SmallVec;
 
+use super::{BasicBlock, Const, Local, UserTypeProjection};
+use crate::mir::coverage::CoverageKind;
+use crate::traits::Reveal;
+use crate::ty::adjustment::PointerCoercion;
+use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex};
+
 /// Represents the "flavors" of MIR.
 ///
 /// All flavors of MIR use the same data structure, but there are some important differences. These
@@ -1583,8 +1578,9 @@ pub enum BinOp {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(AggregateKind<'_>, 32);
     static_assert_size!(Operand<'_>, 24);
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 412cfc1fc7a..1075344dc00 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -3,10 +3,11 @@
  * building is complete.
  */
 
-use crate::mir::*;
 use rustc_hir as hir;
 use tracing::{debug, instrument};
 
+use crate::mir::*;
+
 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct PlaceTy<'tcx> {
     pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 5b035d9579d..962b93a25aa 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -1,14 +1,13 @@
 //! Functionality for terminators and helper types that appear in terminators.
 
-use rustc_hir::LangItem;
-use smallvec::{smallvec, SmallVec};
+use std::slice;
 
-use super::TerminatorKind;
 use rustc_data_structures::packed::Pu128;
+use rustc_hir::LangItem;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use std::slice;
+use smallvec::{smallvec, SmallVec};
 
-use super::*;
+use super::{TerminatorKind, *};
 
 impl SwitchTargets {
     /// Creates switch targets from an iterator of values and target blocks.
@@ -295,9 +294,10 @@ impl<O> AssertKind<O> {
     /// Note that we deliberately show more details here than we do at runtime, such as the actual
     /// numbers that overflowed -- it is much easier to do so here than at runtime.
     pub fn diagnostic_message(&self) -> DiagMessage {
-        use crate::fluent_generated::*;
         use AssertKind::*;
 
+        use crate::fluent_generated::*;
+
         match self {
             BoundsCheck { .. } => middle_bounds_check,
             Overflow(BinOp::Shl, _, _) => middle_assert_shl_overflow,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 0031ded2440..3921176873c 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1066,9 +1066,11 @@ macro_rules! super_body {
 
         $self.visit_span($(& $mutability)? $body.span);
 
-        for const_ in &$($mutability)? $body.required_consts {
-            let location = Location::START;
-            $self.visit_const_operand(const_, location);
+        if let Some(required_consts) = &$($mutability)? $body.required_consts {
+            for const_ in required_consts {
+                let location = Location::START;
+                $self.visit_const_operand(const_, location);
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index d9fa5b02f7f..bd20e6aa005 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -1,10 +1,10 @@
-use crate::mir;
+use std::intrinsics::transmute_unchecked;
+use std::mem::MaybeUninit;
+
 use crate::query::CyclePlaceholder;
-use crate::traits;
 use crate::ty::adjustment::CoerceUnsizedInfo;
 use crate::ty::{self, Ty};
-use std::intrinsics::transmute_unchecked;
-use std::mem::MaybeUninit;
+use crate::{mir, traits};
 
 #[derive(Copy, Clone)]
 pub struct Erased<T: Copy> {
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index add88491f84..6562d46d7b8 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -1,12 +1,5 @@
 //! Defines the set of legal keys that can be used in queries.
 
-use crate::infer::canonical::Canonical;
-use crate::mir;
-use crate::traits;
-use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::layout::{TyAndLayout, ValidityRequirement};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{GenericArg, GenericArgsRef};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE};
 use rustc_hir::hir_id::{HirId, OwnerId};
 use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache};
@@ -14,6 +7,12 @@ use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi;
 
+use crate::infer::canonical::Canonical;
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::layout::{TyAndLayout, ValidityRequirement};
+use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
+use crate::{mir, traits};
+
 /// Placeholder for `CrateNum`'s "local" counterpart
 #[derive(Copy, Clone, Debug)]
 pub struct LocalCrate;
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c7ea1d43383..075eae02904 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -6,7 +6,44 @@
 
 #![allow(unused_parens)]
 
-use crate::dep_graph;
+use std::mem;
+use std::ops::Deref;
+use std::path::PathBuf;
+use std::sync::Arc;
+
+use rustc_arena::TypedArena;
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_ast::expand::StrippedCfgItem;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::steal::Steal;
+use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::unord::{UnordMap, UnordSet};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::{DefKind, DocLinkResMap};
+use rustc_hir::def_id::{
+    CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
+};
+use rustc_hir::lang_items::{LangItem, LanguageItems};
+use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
+use rustc_index::IndexVec;
+use rustc_macros::rustc_queries;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_query_system::query::{try_get_cached, QueryCache, QueryMode, QueryState};
+use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
+use rustc_session::cstore::{
+    CrateDepKind, CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib,
+};
+use rustc_session::lint::LintExpectationId;
+use rustc_session::Limits;
+use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
+use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
+
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintExpectation;
 use crate::metadata::ModChild;
@@ -17,79 +54,35 @@ use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::EffectiveVisibilities;
 use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
 use crate::middle::stability::{self, DeprecationEntry};
-use crate::mir;
-use crate::mir::interpret::GlobalId;
 use crate::mir::interpret::{
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
-    EvalToValTreeResult,
+    EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
 };
-use crate::mir::interpret::{LitToConstError, LitToConstInput};
 use crate::mir::mono::CodegenUnit;
 use crate::query::erase::{erase, restore, Erase};
 use crate::query::plumbing::{
     query_ensure, query_ensure_error_guaranteed, query_get_at, CyclePlaceholder, DynamicQuery,
 };
-use crate::thir;
 use crate::traits::query::{
     CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
     CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
-    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
-};
-use crate::traits::query::{
-    DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult,
+    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, DropckConstraint,
+    DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult,
     OutlivesBound,
 };
-use crate::traits::specialization_graph;
 use crate::traits::{
-    CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause,
-    OverflowError, WellFormedLoc,
+    specialization_graph, CodegenObligationError, EvaluationResult, ImplSource,
+    ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc,
 };
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::layout::ValidityRequirement;
-use crate::ty::print::PrintTraitRefExt;
+use crate::ty::print::{describe_as_module, PrintTraitRefExt};
 use crate::ty::util::AlwaysRequiresDrop;
-use crate::ty::TyCtxtFeed;
 use crate::ty::{
-    self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt,
+    self, CrateInherentImpls, GenericArg, GenericArgsRef, ParamEnvAnd, Ty, TyCtxt, TyCtxtFeed,
     UnusedGenericParams,
 };
-use crate::ty::{GenericArg, GenericArgsRef};
-use rustc_arena::TypedArena;
-use rustc_ast as ast;
-use rustc_ast::expand::{allocator::AllocatorKind, StrippedCfgItem};
-use rustc_attr as attr;
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_data_structures::steal::Steal;
-use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, DocLinkResMap};
-use rustc_hir::def_id::{
-    CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
-};
-use rustc_hir::lang_items::{LangItem, LanguageItems};
-use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
-use rustc_index::IndexVec;
-use rustc_macros::rustc_queries;
-use rustc_query_system::ich::StableHashingContext;
-use rustc_query_system::query::{try_get_cached, QueryCache, QueryMode, QueryState};
-use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
-use rustc_session::cstore::{CrateDepKind, CrateSource};
-use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
-use rustc_session::lint::LintExpectationId;
-use rustc_session::Limits;
-use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::symbol::Symbol;
-use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi;
-use rustc_target::spec::PanicStrategy;
-use std::mem;
-use std::ops::Deref;
-use std::path::PathBuf;
-use std::sync::Arc;
+use crate::{dep_graph, mir, thir};
 
 pub mod erase;
 mod keys;
@@ -414,6 +407,10 @@ rustc_queries! {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
+    query impl_super_outlives(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
+        desc { |tcx| "elaborating supertrait outlives for trait of `{}`", tcx.def_path_str(key) }
+    }
+
     /// Look up all native libraries this crate depends on.
     /// These are assembled from the following places:
     /// - `extern` blocks (depending on their `link` attributes)
@@ -1729,6 +1726,10 @@ rustc_queries! {
         desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
     }
 
+    query inherit_sig_for_delegation_item(def_id: LocalDefId) -> &'tcx [Ty<'tcx>] {
+        desc { "inheriting delegation signature" }
+    }
+
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes` for details.
@@ -2186,6 +2187,12 @@ rustc_queries! {
         desc { "looking up supported target features" }
     }
 
+    query implied_target_features(feature: Symbol) -> &'tcx Vec<Symbol> {
+        arena_cache
+        eval_always
+        desc { "looking up implied target features" }
+    }
+
     query features_query(_: ()) -> &'tcx rustc_feature::Features {
         feedable
         desc { "looking up enabled feature gates" }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 924249bf37d..ca52358218e 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -1,3 +1,6 @@
+use std::collections::hash_map::Entry;
+use std::mem;
+
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
@@ -13,22 +16,17 @@ use rustc_middle::mir::{self, interpret};
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_query_system::query::QuerySideEffects;
-use rustc_serialize::{
-    opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder},
-    Decodable, Decoder, Encodable, Encoder,
-};
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_session::Session;
 use rustc_span::hygiene::{
     ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
 };
 use rustc_span::source_map::SourceMap;
 use rustc_span::{
-    BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder,
-    StableSourceFileId,
+    BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span,
+    SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
 };
-use rustc_span::{CachingSourceMapView, Symbol};
-use std::collections::hash_map::Entry;
-use std::mem;
 
 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
 
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 8a4e3ab0e61..c9bd702cce3 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -1,25 +1,23 @@
-use crate::dep_graph;
-use crate::dep_graph::DepKind;
-use crate::query::on_disk_cache::CacheEncoder;
-use crate::query::on_disk_cache::EncodedDepNodeIndex;
-use crate::query::on_disk_cache::OnDiskCache;
-use crate::query::{
-    DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
-};
-use crate::ty::TyCtxt;
+use std::ops::Deref;
+
 use field_offset::FieldOffset;
-use rustc_data_structures::sync::AtomicU64;
-use rustc_data_structures::sync::WorkerLocal;
+use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::hir_id::OwnerId;
 use rustc_macros::HashStable;
-use rustc_query_system::dep_graph::DepNodeIndex;
-use rustc_query_system::dep_graph::SerializedDepNodeIndex;
+use rustc_query_system::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 pub(crate) use rustc_query_system::query::QueryJobId;
 use rustc_query_system::query::*;
 use rustc_query_system::HandleCycleError;
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
-use std::ops::Deref;
+
+use crate::dep_graph;
+use crate::dep_graph::DepKind;
+use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
+use crate::query::{
+    DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
+};
+use crate::ty::TyCtxt;
 
 pub struct DynamicQuery<'tcx, C: QueryCache> {
     pub name: &'static str,
@@ -574,9 +572,10 @@ macro_rules! define_feedable {
 // as they will raise an fatal error on query cycles instead.
 
 mod sealed {
-    use super::{DefId, LocalDefId, OwnerId};
     use rustc_hir::def_id::{LocalModDefId, ModDefId};
 
+    use super::{DefId, LocalDefId, OwnerId};
+
     /// An analogue of the `Into` trait that's intended only for query parameters.
     ///
     /// This exists to allow queries to accept either `DefId` or `LocalDefId` while requiring that the
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index b80d00719ee..f2ea32275f9 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -8,13 +8,15 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
 
+use std::cmp::Ordering;
+use std::fmt;
+use std::ops::Index;
+
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
-use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
-use rustc_index::newtype_index;
-use rustc_index::IndexVec;
+use rustc_index::{newtype_index, IndexVec};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::AllocId;
@@ -26,12 +28,9 @@ use rustc_middle::ty::{
     TyCtxt, UpvarArgs,
 };
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx};
 use rustc_target::asm::InlineAsmRegOrRegClass;
-use std::cmp::Ordering;
-use std::fmt;
-use std::ops::Index;
 use tracing::instrument;
 
 pub mod visit;
@@ -598,10 +597,6 @@ pub struct Pat<'tcx> {
 }
 
 impl<'tcx> Pat<'tcx> {
-    pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
-        Pat { ty, span: DUMMY_SP, kind: PatKind::Wild }
-    }
-
     pub fn simple_ident(&self) -> Option<Symbol> {
         match self.kind {
             PatKind::Binding {
@@ -702,12 +697,6 @@ impl<'tcx> Pat<'tcx> {
     }
 }
 
-impl<'tcx> IntoDiagArg for Pat<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        format!("{self}").into_diag_arg()
-    }
-}
-
 #[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct Ascription<'tcx> {
     pub annotation: CanonicalUserTypeAnnotation<'tcx>,
@@ -1080,164 +1069,12 @@ impl<'tcx> PatRangeBoundary<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Display for Pat<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Printing lists is a chore.
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
-        match self.kind {
-            PatKind::Wild => write!(f, "_"),
-            PatKind::Never => write!(f, "!"),
-            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
-            PatKind::Binding { name, mode, ref subpattern, .. } => {
-                f.write_str(mode.prefix_str())?;
-                write!(f, "{name}")?;
-                if let Some(ref subpattern) = *subpattern {
-                    write!(f, " @ {subpattern}")?;
-                }
-                Ok(())
-            }
-            PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
-                let variant_and_name = match self.kind {
-                    PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
-                        let variant = adt_def.variant(variant_index);
-                        let adt_did = adt_def.did();
-                        let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
-                            || tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
-                        {
-                            variant.name.to_string()
-                        } else {
-                            format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
-                        };
-                        Some((variant, name))
-                    }),
-                    _ => self.ty.ty_adt_def().and_then(|adt_def| {
-                        if !adt_def.is_enum() {
-                            ty::tls::with(|tcx| {
-                                Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
-                            })
-                        } else {
-                            None
-                        }
-                    }),
-                };
-
-                if let Some((variant, name)) = &variant_and_name {
-                    write!(f, "{name}")?;
-
-                    // Only for Adt we can have `S {...}`,
-                    // which we handle separately here.
-                    if variant.ctor.is_none() {
-                        write!(f, " {{ ")?;
-
-                        let mut printed = 0;
-                        for p in subpatterns {
-                            if let PatKind::Wild = p.pattern.kind {
-                                continue;
-                            }
-                            let name = variant.fields[p.field].name;
-                            write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
-                            printed += 1;
-                        }
-
-                        let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
-                        if printed < variant.fields.len() && (!is_union || printed == 0) {
-                            write!(f, "{}..", start_or_comma())?;
-                        }
-
-                        return write!(f, " }}");
-                    }
-                }
-
-                let num_fields =
-                    variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
-                if num_fields != 0 || variant_and_name.is_none() {
-                    write!(f, "(")?;
-                    for i in 0..num_fields {
-                        write!(f, "{}", start_or_comma())?;
-
-                        // Common case: the field is where we expect it.
-                        if let Some(p) = subpatterns.get(i) {
-                            if p.field.index() == i {
-                                write!(f, "{}", p.pattern)?;
-                                continue;
-                            }
-                        }
-
-                        // Otherwise, we have to go looking for it.
-                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
-                            write!(f, "{}", p.pattern)?;
-                        } else {
-                            write!(f, "_")?;
-                        }
-                    }
-                    write!(f, ")")?;
-                }
-
-                Ok(())
-            }
-            PatKind::Deref { ref subpattern } => {
-                match self.ty.kind() {
-                    ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
-                    ty::Ref(_, _, mutbl) => {
-                        write!(f, "&{}", mutbl.prefix_str())?;
-                    }
-                    _ => bug!("{} is a bad Deref pattern type", self.ty),
-                }
-                write!(f, "{subpattern}")
-            }
-            PatKind::DerefPattern { ref subpattern, .. } => {
-                write!(f, "deref!({subpattern})")
-            }
-            PatKind::Constant { value } => write!(f, "{value}"),
-            PatKind::InlineConstant { def: _, ref subpattern } => {
-                write!(f, "{} (from inline const)", subpattern)
-            }
-            PatKind::Range(ref range) => write!(f, "{range}"),
-            PatKind::Slice { ref prefix, ref slice, ref suffix }
-            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                write!(f, "[")?;
-                for p in prefix.iter() {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                if let Some(ref slice) = *slice {
-                    write!(f, "{}", start_or_comma())?;
-                    match slice.kind {
-                        PatKind::Wild => {}
-                        _ => write!(f, "{slice}")?,
-                    }
-                    write!(f, "..")?;
-                }
-                for p in suffix.iter() {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                write!(f, "]")
-            }
-            PatKind::Or { ref pats } => {
-                for pat in pats.iter() {
-                    write!(f, "{}{}", start_or_continue(" | "), pat)?;
-                }
-                Ok(())
-            }
-            PatKind::Error(_) => write!(f, "<error>"),
-        }
-    }
-}
-
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Block, 48);
     static_assert_size!(Expr<'_>, 64);
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index b74775142e4..d54e2ca0a74 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -8,10 +8,8 @@ pub mod solve;
 pub mod specialization_graph;
 mod structural_impls;
 
-use crate::mir::ConstraintCategory;
-use crate::ty::abstract_const::NotConstEvaluatable;
-use crate::ty::GenericArgsRef;
-use crate::ty::{self, AdtKind, Ty};
+use std::borrow::Cow;
+use std::hash::{Hash, Hasher};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee};
@@ -24,14 +22,14 @@ use rustc_macros::{
 use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
+// FIXME: Remove this import and import via `solve::`
+pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal};
 use smallvec::{smallvec, SmallVec};
 
-use std::borrow::Cow;
-use std::hash::{Hash, Hasher};
-
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
-// FIXME: Remove this import and import via `solve::`
-pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal};
+use crate::mir::ConstraintCategory;
+use crate::ty::abstract_const::NotConstEvaluatable;
+use crate::ty::{self, AdtKind, GenericArgsRef, Ty};
 
 /// The reason why we incurred this obligation; used for error reporting.
 ///
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 4fad721ce98..81a543e647a 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -5,20 +5,22 @@
 //! The providers for the queries defined here can be found in
 //! `rustc_traits`.
 
-use crate::error::DropCheckOverflow;
-use crate::infer::canonical::{Canonical, QueryResponse};
-use crate::ty::GenericArg;
-use crate::ty::{self, Ty, TyCtxt};
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
 // FIXME: Remove this import and import via `traits::solve`.
 pub use rustc_type_ir::solve::NoSolution;
 
+use crate::error::DropCheckOverflow;
+use crate::infer::canonical::{Canonical, QueryResponse};
+use crate::ty::{self, GenericArg, Ty, TyCtxt};
+
 pub mod type_op {
+    use std::fmt;
+
+    use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
+
     use crate::ty::fold::TypeFoldable;
     use crate::ty::{Predicate, Ty, TyCtxt, UserType};
-    use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
-    use std::fmt;
 
     #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct AscribeUserType<'tcx> {
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index c8caf228ffb..66035464fa5 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -2,17 +2,15 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
-use self::EvaluationResult::*;
-
-use super::{SelectionError, SelectionResult};
 use rustc_errors::ErrorGuaranteed;
-
-use crate::ty;
-
 use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, TypeVisitable};
 use rustc_query_system::cache::Cache;
 
+use self::EvaluationResult::*;
+use super::{SelectionError, SelectionResult};
+use crate::ty;
+
 pub type SelectionCache<'tcx> = Cache<
     // This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace
     // caller bounds with an empty list if the `TraitPredicate` looks global, which may happen
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index ff5d51bcb66..26dcae001e0 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -1,13 +1,14 @@
-use crate::error::StrictCoherenceNeedsNegativeCoherence;
-use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::visit::TypeVisitableExt;
-use crate::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::symbol::sym;
 
+use crate::error::StrictCoherenceNeedsNegativeCoherence;
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::visit::TypeVisitableExt;
+use crate::ty::{self, TyCtxt};
+
 /// A per-trait graph of impls in specialization order. At the moment, this
 /// graph forms a tree rooted with the trait itself, with all other nodes
 /// representing impls, and parent-child relationships representing
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index ec450cf5590..d79a9368f34 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -1,7 +1,7 @@
-use crate::traits;
-
 use std::fmt;
 
+use crate::traits;
+
 // Structural impls for the structs in `traits`.
 
 impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index 3aa01fbef2f..002d3819621 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -1,11 +1,12 @@
 //! A subset of a mir body used for const evaluability checking.
 
+use rustc_errors::ErrorGuaranteed;
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
+
 use crate::ty::{
     self, Const, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeVisitableExt,
 };
-use rustc_errors::ErrorGuaranteed;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
 
 #[derive(Hash, Debug, Clone, Copy, Ord, PartialOrd, PartialEq, Eq)]
 #[derive(TyDecodable, TyEncodable, HashStable, TypeVisitable, TypeFoldable)]
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 6d7b6259747..1236c9efb41 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -1,10 +1,11 @@
-use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
 use rustc_target::abi::FieldIdx;
 
+use crate::ty::{self, Ty, TyCtxt};
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum PointerCoercion {
     /// Go from a fn-item type to a fn-pointer type.
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 88ee32eae95..204f61b4804 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -1,12 +1,13 @@
-use crate::mir::interpret::ErrorHandled;
-use crate::ty;
-use crate::ty::util::{Discr, IntTypeExt};
+use std::cell::RefCell;
+use std::hash::{Hash, Hasher};
+use std::ops::Range;
+use std::str;
+
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::intern::Interned;
-use rustc_data_structures::stable_hasher::HashingControls;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -19,14 +20,12 @@ use rustc_span::symbol::sym;
 use rustc_target::abi::{ReprOptions, VariantIdx, FIRST_VARIANT};
 use tracing::{debug, info, trace};
 
-use std::cell::RefCell;
-use std::hash::{Hash, Hasher};
-use std::ops::Range;
-use std::str;
-
 use super::{
     AsyncDestructor, Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, VariantDiscr,
 };
+use crate::mir::interpret::ErrorHandled;
+use crate::ty;
+use crate::ty::util::{Discr, IntTypeExt};
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
 pub struct AdtFlags(u16);
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 820f5e950a9..db56e0016a2 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -1,4 +1,3 @@
-use crate::ty;
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
@@ -7,6 +6,7 @@ use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_span::symbol::{Ident, Symbol};
 
 use super::{TyCtxt, Visibility};
+use crate::ty;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
 pub enum AssocItemContainer {
@@ -98,6 +98,15 @@ impl AssocItem {
         }
     }
 
+    pub fn descr(&self) -> &'static str {
+        match self.kind {
+            ty::AssocKind::Const => "const",
+            ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
+            ty::AssocKind::Fn => "associated function",
+            ty::AssocKind::Type => "type",
+        }
+    }
+
     pub fn is_impl_trait_in_trait(&self) -> bool {
         self.opt_rpitit_info.is_some()
     }
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 26c5a865fdc..46f37659536 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -1,10 +1,10 @@
 // Helpers for handling cast expressions, used in both
 // typeck and codegen.
 
-use crate::ty::{self, Ty};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_middle::mir;
 
-use rustc_macros::{HashStable, TyDecodable, TyEncodable};
+use crate::ty::{self, Ty};
 
 /// Types that are represented as ints.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index bdd9a6bab2b..8eb3c015679 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -1,11 +1,5 @@
-use crate::hir::place::{
-    Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
-};
-use crate::{mir, ty};
-
 use std::fmt::Write;
 
-use crate::query::Providers;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
@@ -16,9 +10,13 @@ use rustc_span::def_id::LocalDefIdMap;
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, Symbol};
 
-use super::TyCtxt;
-
 use self::BorrowKind::*;
+use super::TyCtxt;
+use crate::hir::place::{
+    Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
+};
+use crate::query::Providers;
+use crate::{mir, ty};
 
 /// Captures are represented using fields inside a structure.
 /// This represents accessing self in the closure structure
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 33f564e9b59..401f6da6526 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -6,16 +6,10 @@
 //! The functionality in here is shared between persisting to crate metadata and
 //! persisting to incr. comp. caches.
 
-use crate::arena::ArenaAllocatable;
-use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
-use crate::mir::interpret::CtfeProvenance;
-use crate::mir::{
-    self,
-    interpret::{AllocId, ConstAllocation},
-};
-use crate::traits;
-use crate::ty::GenericArgsRef;
-use crate::ty::{self, AdtDef, Ty};
+use std::hash::Hash;
+use std::intrinsics;
+use std::marker::DiscriminantKind;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
@@ -23,9 +17,13 @@ use rustc_serialize::{Decodable, Encodable};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 pub use rustc_type_ir::{TyDecoder, TyEncoder};
-use std::hash::Hash;
-use std::intrinsics;
-use std::marker::DiscriminantKind;
+
+use crate::arena::ArenaAllocatable;
+use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
+use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance};
+use crate::mir::{self};
+use crate::traits;
+use crate::ty::{self, AdtDef, GenericArgsRef, Ty};
 
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 5cf1247f0c8..c380019e63f 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,6 +1,3 @@
-use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
-use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use either::Either;
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
@@ -11,14 +8,17 @@ use rustc_macros::HashStable;
 use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
+use crate::middle::resolve_bound_vars as rbv;
+use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
+use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+
 mod int;
 mod kind;
 mod valtree;
 
 pub use int::*;
 pub use kind::*;
-use rustc_span::DUMMY_SP;
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 pub use valtree::*;
 
 pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 13691b61941..0024a2ae756 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -1,10 +1,11 @@
+use std::fmt;
+use std::num::NonZero;
+
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_apfloat::Float;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_target::abi::Size;
-use std::fmt;
-use std::num::NonZero;
 
 use crate::ty::TyCtxt;
 
@@ -233,7 +234,7 @@ impl ScalarInt {
         let data = i.into();
         // `into` performed sign extension, we have to truncate
         let r = Self::raw(size.truncate(data as u128), size);
-        (r, size.sign_extend(r.data) as i128 != data)
+        (r, size.sign_extend(r.data) != data)
     }
 
     #[inline]
@@ -334,7 +335,7 @@ impl ScalarInt {
     #[inline]
     pub fn to_int(self, size: Size) -> i128 {
         let b = self.to_bits(size);
-        size.sign_extend(b) as i128
+        size.sign_extend(b)
     }
 
     /// Converts the `ScalarInt` to i8.
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 98f35b6b8ab..c7c2e8afa1e 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,8 +1,12 @@
+use std::assert_matches::assert_matches;
+
+use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+
 use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
-use crate::ty::{self, visit::TypeVisitableExt as _, Ty, TyCtxt};
-use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+use crate::ty::visit::TypeVisitableExt as _;
+use crate::ty::{self, Ty, TyCtxt};
 
 #[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
 impl<'tcx> ty::UnevaluatedConst<'tcx> {
@@ -78,7 +82,7 @@ impl<'tcx> Expr<'tcx> {
     }
 
     pub fn binop_args(self) -> (Ty<'tcx>, Ty<'tcx>, Const<'tcx>, Const<'tcx>) {
-        assert!(matches!(self.kind, ExprKind::Binop(_)));
+        assert_matches!(self.kind, ExprKind::Binop(_));
 
         match self.args().as_slice() {
             [lhs_ty, rhs_ty, lhs_ct, rhs_ct] => (
@@ -99,7 +103,7 @@ impl<'tcx> Expr<'tcx> {
     }
 
     pub fn unop_args(self) -> (Ty<'tcx>, Const<'tcx>) {
-        assert!(matches!(self.kind, ExprKind::UnOp(_)));
+        assert_matches!(self.kind, ExprKind::UnOp(_));
 
         match self.args().as_slice() {
             [ty, ct] => (ty.expect_ty(), ct.expect_const()),
@@ -123,7 +127,7 @@ impl<'tcx> Expr<'tcx> {
     }
 
     pub fn call_args(self) -> (Ty<'tcx>, Const<'tcx>, impl Iterator<Item = Const<'tcx>>) {
-        assert!(matches!(self.kind, ExprKind::FunctionCall));
+        assert_matches!(self.kind, ExprKind::FunctionCall);
 
         match self.args().as_slice() {
             [func_ty, func, rest @ ..] => (
@@ -150,7 +154,7 @@ impl<'tcx> Expr<'tcx> {
     }
 
     pub fn cast_args(self) -> (Ty<'tcx>, Const<'tcx>, Ty<'tcx>) {
-        assert!(matches!(self.kind, ExprKind::Cast(_)));
+        assert_matches!(self.kind, ExprKind::Cast(_));
 
         match self.args().as_slice() {
             [value_ty, value, to_ty] => {
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index efc91357af8..9f9bf41c335 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -1,7 +1,8 @@
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
+
 use super::ScalarInt;
 use crate::mir::interpret::Scalar;
 use crate::ty::{self, Ty, TyCtxt};
-use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 
 #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq)]
 #[derive(HashStable)]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index fd41668ae44..971e51be256 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -4,36 +4,14 @@
 
 pub mod tls;
 
-pub use rustc_type_ir::lift::Lift;
+use std::assert_matches::assert_matches;
+use std::borrow::Borrow;
+use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::ops::{Bound, Deref};
+use std::{fmt, iter, mem};
 
-use crate::arena::Arena;
-use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
-use crate::lint::lint_level;
-use crate::metadata::ModChild;
-use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::resolve_bound_vars;
-use crate::middle::stability;
-use crate::mir::interpret::{self, Allocation, ConstAllocation};
-use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
-use crate::query::plumbing::QuerySystem;
-use crate::query::LocalCrate;
-use crate::query::Providers;
-use crate::query::{IntoQueryParam, TyCtxtAt};
-use crate::thir::Thir;
-use crate::traits;
-use crate::traits::solve;
-use crate::traits::solve::{
-    ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
-};
-use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
-use crate::ty::{
-    self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericParamDefKind,
-    ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind,
-    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
-    RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility,
-};
-use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_ast::{self as ast, attr};
 use rustc_data_structures::defer;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -74,20 +52,37 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}
 use rustc_target::spec::abi;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+pub use rustc_type_ir::lift::Lift;
 use rustc_type_ir::solve::SolverMode;
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
-use std::assert_matches::assert_matches;
-use std::borrow::Borrow;
-use std::cmp::Ordering;
-use std::fmt;
-use std::hash::{Hash, Hasher};
-use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::{Bound, Deref};
+use crate::arena::Arena;
+use crate::dep_graph::{DepGraph, DepKindStruct};
+use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
+use crate::lint::lint_level;
+use crate::metadata::ModChild;
+use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
+use crate::middle::{resolve_bound_vars, stability};
+use crate::mir::interpret::{self, Allocation, ConstAllocation};
+use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::query::plumbing::QuerySystem;
+use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt};
+use crate::thir::Thir;
+use crate::traits;
+use crate::traits::solve;
+use crate::traits::solve::{
+    ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
+};
+use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
+use crate::ty::{
+    self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs,
+    GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst,
+    ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind,
+    PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
+    Visibility,
+};
 
 #[allow(rustc::usage_of_ty_tykind)]
 impl<'tcx> Interner for TyCtxt<'tcx> {
@@ -1443,11 +1438,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     /// Returns the same `AllocId` if called again with the same bytes.
-    pub fn allocate_bytes_dedup(self, bytes: &[u8]) -> interpret::AllocId {
+    pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> 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_dedup(alloc)
+        self.reserve_and_set_memory_dedup(alloc, salt)
     }
 
     /// Returns a range of the start/end indices specified with the
@@ -3181,6 +3176,12 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn impl_polarity(self, def_id: impl IntoQueryParam<DefId>) -> ty::ImplPolarity {
         self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity)
     }
+
+    /// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
+    pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
+        matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true })
+            && self.impl_trait_header(def_id).is_some_and(|header| header.do_not_recommend)
+    }
 }
 
 /// Parameter attributes that can only be determined by examining the body of a function instead
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
index 7b5ccae3568..6a5d3030646 100644
--- a/compiler/rustc_middle/src/ty/context/tls.rs
+++ b/compiler/rustc_middle/src/ty/context/tls.rs
@@ -1,15 +1,15 @@
-use super::{GlobalCtxt, TyCtxt};
+#[cfg(not(parallel_compiler))]
+use std::cell::Cell;
+use std::{mem, ptr};
 
-use crate::dep_graph::TaskDepsRef;
-use crate::query::plumbing::QueryJobId;
 use rustc_data_structures::sync::{self, Lock};
 use rustc_errors::DiagInner;
-#[cfg(not(parallel_compiler))]
-use std::cell::Cell;
-use std::mem;
-use std::ptr;
 use thin_vec::ThinVec;
 
+use super::{GlobalCtxt, TyCtxt};
+use crate::dep_graph::TaskDepsRef;
+use crate::query::plumbing::QueryJobId;
+
 /// This is the implicit state of rustc. It contains the current
 /// `TyCtxt` and query. It is updated when creating a local interner or
 /// executing a new query. Whenever there's a `TyCtxt` value available
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index f2261f4a43b..5acc0b7ac7f 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -4,12 +4,6 @@ use std::borrow::Cow;
 use std::fmt::Write;
 use std::ops::ControlFlow;
 
-use crate::ty::{
-    self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque,
-    PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitor,
-};
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{into_diag_arg_using_display, Applicability, Diag, DiagArgValue, IntoDiagArg};
 use rustc_hir as hir;
@@ -19,6 +13,12 @@ use rustc_hir::{PredicateOrigin, WherePredicate};
 use rustc_span::{BytePos, Span};
 use rustc_type_ir::TyKind::*;
 
+use crate::ty::{
+    self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque,
+    PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitor,
+};
+
 into_diag_arg_using_display! {
     Ty<'_>,
     ty::Region<'_>,
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 9d5481f3df3..ecca1d44907 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,7 +1,8 @@
+use tracing::debug;
+
 use crate::query::Providers;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::{self, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
-use tracing::debug;
 
 pub(super) fn provide(providers: &mut Providers) {
     *providers = Providers { erase_regions_ty, ..*providers };
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 32dc9fa5fc6..2f9bdb16bb0 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -1,5 +1,6 @@
-use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
-use crate::ty::{self, Ty, TyCtxt};
+use std::borrow::Cow;
+use std::hash::{DefaultHasher, Hash, Hasher};
+use std::path::PathBuf;
 
 use rustc_errors::pluralize;
 use rustc_hir as hir;
@@ -7,9 +8,8 @@ use rustc_hir::def::{CtorOf, DefKind};
 use rustc_macros::extension;
 pub use rustc_type_ir::error::ExpectedFound;
 
-use std::borrow::Cow;
-use std::hash::{DefaultHasher, Hash, Hasher};
-use std::path::PathBuf;
+use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
+use crate::ty::{self, Ty, TyCtxt};
 
 pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>;
 
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 0413cfa5a63..91344c4e39c 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,9 +1,8 @@
 use rustc_hir::def_id::DefId;
+pub use rustc_type_ir::fast_reject::*;
 
 use super::TyCtxt;
 
-pub use rustc_type_ir::fast_reject::*;
-
 pub type DeepRejectCtxt<'tcx> = rustc_type_ir::fast_reject::DeepRejectCtxt<TyCtxt<'tcx>>;
 
 pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType<DefId>;
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 21c115c2c96..c3430b58406 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -1,7 +1,7 @@
-use crate::ty::{self, InferConst, Ty, TypeFlags};
-use crate::ty::{GenericArg, GenericArgKind};
 use std::slice;
 
+use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags};
+
 #[derive(Debug)]
 pub struct FlagComputation {
     pub flags: TypeFlags,
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 81ea8738e72..7892ef81819 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1,11 +1,11 @@
-use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitableExt};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
-use tracing::{debug, instrument};
-
 pub use rustc_type_ir::fold::{
     shift_region, shift_vars, FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable,
 };
+use tracing::{debug, instrument};
+
+use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitableExt};
 
 ///////////////////////////////////////////////////////////////////////////
 // Some sample folders
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 10919623de7..80c31e236e2 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -1,28 +1,27 @@
 // Generic arguments.
 
-use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
-use crate::ty::visit::{TypeVisitable, TypeVisitor};
-use crate::ty::{
-    self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt,
-};
+use core::intrinsics;
+use std::marker::PhantomData;
+use std::mem;
+use std::num::NonZero;
+use std::ptr::NonNull;
 
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_ast_ir::walk_visitable_list;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir::def_id::DefId;
-use rustc_macros::extension;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_serialize::{Decodable, Encodable};
 use rustc_type_ir::WithCachedTypeInfo;
 use smallvec::SmallVec;
 
-use core::intrinsics;
-use std::marker::PhantomData;
-use std::mem;
-use std::num::NonZero;
-use std::ptr::NonNull;
+use crate::ty::codec::{TyDecoder, TyEncoder};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
+use crate::ty::{
+    self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt,
+};
 
 pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
 pub type TermKind<'tcx> = rustc_type_ir::TermKind<TyCtxt<'tcx>>;
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 11ed0bdaa70..8cb8e9af11c 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -1,5 +1,3 @@
-use crate::ty;
-use crate::ty::{EarlyBinder, GenericArgsRef};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
@@ -9,6 +7,8 @@ use rustc_span::Span;
 use tracing::instrument;
 
 use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt};
+use crate::ty;
+use crate::ty::{EarlyBinder, GenericArgsRef};
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum GenericParamDefKind {
@@ -376,7 +376,7 @@ pub struct GenericPredicates<'tcx> {
 
 impl<'tcx> GenericPredicates<'tcx> {
     pub fn instantiate(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> InstantiatedPredicates<'tcx> {
@@ -386,20 +386,20 @@ impl<'tcx> GenericPredicates<'tcx> {
     }
 
     pub fn instantiate_own(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
         EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
     }
 
-    pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
+    pub fn instantiate_own_identity(self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
         EarlyBinder::bind(self.predicates).iter_identity_copied()
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
     fn instantiate_into(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         instantiated: &mut InstantiatedPredicates<'tcx>,
         args: GenericArgsRef<'tcx>,
@@ -413,14 +413,14 @@ impl<'tcx> GenericPredicates<'tcx> {
         instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
     }
 
-    pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
+    pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
         let mut instantiated = InstantiatedPredicates::empty();
         self.instantiate_identity_into(tcx, &mut instantiated);
         instantiated
     }
 
     fn instantiate_identity_into(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         instantiated: &mut InstantiatedPredicates<'tcx>,
     ) {
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 9be7370a1c2..b5b7b8bcfef 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -1,18 +1,20 @@
 //! This module contains `HashStable` implementations for various data types
 //! from `rustc_middle::ty` in no particular order.
 
-use crate::middle::region;
-use crate::mir;
-use crate::ty;
+use std::cell::RefCell;
+use std::ptr;
+
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::HashingControls;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{
+    HashStable, HashingControls, StableHasher, ToStableHashKey,
+};
 use rustc_query_system::ich::StableHashingContext;
-use std::cell::RefCell;
-use std::ptr;
 use tracing::trace;
 
+use crate::middle::region;
+use crate::{mir, ty};
+
 impl<'a, 'tcx, H, T> HashStable<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T>
 where
     T: HashStable<StableHashingContext<'a>>,
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index afdf2cbc726..698104b0462 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -43,13 +43,13 @@
 //! This code should only compile in modules where the uninhabitedness of `Foo`
 //! is visible.
 
+use rustc_type_ir::TyKind::*;
+use tracing::instrument;
+
 use crate::query::Providers;
 use crate::ty::context::TyCtxt;
 use crate::ty::{self, DefId, Ty, TypeVisitableExt, VariantDef, Visibility};
 
-use rustc_type_ir::TyKind::*;
-use tracing::instrument;
-
 pub mod inhabited_predicate;
 
 pub use inhabited_predicate::InhabitedPredicate;
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 6e64e9bc4f8..0496c571f5e 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,10 +1,7 @@
-use crate::error;
-use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer};
-use crate::ty::{
-    self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
-};
+use std::assert_matches::assert_matches;
+use std::fmt;
+use std::path::PathBuf;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
@@ -18,9 +15,13 @@ use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use tracing::{debug, instrument};
 
-use std::assert_matches::assert_matches;
-use std::fmt;
-use std::path::PathBuf;
+use crate::error;
+use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer};
+use crate::ty::{
+    self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
 
 /// An `InstanceKind` along with the args that are needed to substitute the instance.
 ///
diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs
index 68c1d8c17ec..41a966da8aa 100644
--- a/compiler/rustc_middle/src/ty/intrinsic.rs
+++ b/compiler/rustc_middle/src/ty/intrinsic.rs
@@ -1,5 +1,6 @@
 use rustc_macros::{Decodable, Encodable, HashStable};
-use rustc_span::{def_id::DefId, Symbol};
+use rustc_span::def_id::DefId;
+use rustc_span::Symbol;
 
 use super::TyCtxt;
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 22a6786665c..684574825e3 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,8 +1,8 @@
-use crate::error::UnsupportedFnAbi;
-use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::query::TyCtxtAt;
-use crate::ty::normalize_erasing_regions::NormalizationError;
-use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};
+use std::borrow::Cow;
+use std::num::NonZero;
+use std::ops::Bound;
+use std::{cmp, fmt};
+
 use rustc_error_messages::DiagMessage;
 use rustc_errors::{
     Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
@@ -17,16 +17,15 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::*;
-use rustc_target::spec::{
-    abi::Abi as SpecAbi, HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi,
-};
+use rustc_target::spec::abi::Abi as SpecAbi;
+use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi};
 use tracing::debug;
 
-use std::borrow::Cow;
-use std::cmp;
-use std::fmt;
-use std::num::NonZero;
-use std::ops::Bound;
+use crate::error::UnsupportedFnAbi;
+use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::query::TyCtxtAt;
+use crate::ty::normalize_erasing_regions::NormalizationError;
+use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};
 
 #[extension(pub trait IntegerExt)]
 impl Integer {
@@ -231,8 +230,9 @@ pub enum LayoutError<'tcx> {
 
 impl<'tcx> LayoutError<'tcx> {
     pub fn diagnostic_message(&self) -> DiagMessage {
-        use crate::fluent_generated::*;
         use LayoutError::*;
+
+        use crate::fluent_generated::*;
         match self {
             Unknown(_) => middle_unknown_layout,
             SizeOverflow(_) => middle_values_too_big,
@@ -243,8 +243,9 @@ impl<'tcx> LayoutError<'tcx> {
     }
 
     pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> {
-        use crate::error::LayoutError as E;
         use LayoutError::*;
+
+        use crate::error::LayoutError as E;
         match self {
             Unknown(ty) => E::Unknown { ty },
             SizeOverflow(ty) => E::Overflow { ty },
@@ -361,7 +362,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
             ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                 let non_zero = !ty.is_unsafe_ptr();
 
-                let tail = tcx.struct_tail_with_normalize(
+                let tail = tcx.struct_tail_raw(
                     pointee,
                     |ty| match tcx.try_normalize_erasing_regions(param_env, ty) {
                         Ok(ty) => ty,
@@ -868,7 +869,7 @@ where
                             metadata
                         }
                     } else {
-                        match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+                        match tcx.struct_tail_for_codegen(pointee, cx.param_env()).kind() {
                             ty::Slice(_) | ty::Str => tcx.types.usize,
                             ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
                             _ => bug!("TyAndLayout::field({:?}): not applicable", this),
@@ -1347,7 +1348,7 @@ impl<'tcx> TyCtxt<'tcx> {
             layout = layout.field(&cx, index);
             if !layout.is_sized() {
                 // If it is not sized, then the tail must still have at least a known static alignment.
-                let tail = self.struct_tail_erasing_lifetimes(layout.ty, param_env);
+                let tail = self.struct_tail_for_codegen(layout.ty, param_env);
                 if !matches!(tail.kind(), ty::Slice(..)) {
                     bug!(
                         "offset of not-statically-aligned field (type {:?}) cannot be computed statically",
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 73eba93194e..1a1acf36d77 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,20 +1,17 @@
-use super::flags::FlagComputation;
-use super::{DebruijnIndex, TypeFlags};
-use crate::arena::Arena;
-use rustc_data_structures::aligned::{align_of, Aligned};
-use rustc_serialize::{Encodable, Encoder};
 use std::alloc::Layout;
 use std::cmp::Ordering;
-use std::fmt;
 use std::hash::{Hash, Hasher};
-use std::iter;
-use std::mem;
 use std::ops::Deref;
-use std::ptr;
-use std::slice;
+use std::{fmt, iter, mem, ptr, slice};
 
+use rustc_data_structures::aligned::{align_of, Aligned};
 #[cfg(parallel_compiler)]
 use rustc_data_structures::sync::DynSync;
+use rustc_serialize::{Encodable, Encoder};
+
+use super::flags::FlagComputation;
+use super::{DebruijnIndex, TypeFlags};
+use crate::arena::Arena;
 
 /// `List<T>` is a bit like `&[T]`, but with some critical differences.
 /// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 558590af7ec..69b194045ad 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -11,37 +11,28 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
-pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
-pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-pub use self::AssocItemContainer::*;
-pub use self::BorrowKind::*;
-pub use self::IntVarValue::*;
-use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
-use crate::metadata::ModChild;
-use crate::middle::privacy::EffectiveVisibilities;
-use crate::mir::{Body, CoroutineLayout};
-use crate::query::Providers;
-use crate::traits::{self, Reveal};
-use crate::ty;
-use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::util::Discr;
+use std::assert_matches::assert_matches;
+use std::fmt::Debug;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::num::NonZero;
+use std::ptr::NonNull;
+use std::{fmt, mem, str};
+
 pub use adt::*;
 pub use assoc::*;
 pub use generic_args::{GenericArgKind, TermKind, *};
 pub use generics::*;
 pub use intrinsic::IntrinsicDef;
-use rustc_ast as ast;
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
 pub use rustc_ast_ir::{try_visit, Movability, Mutability};
-use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
 use rustc_index::IndexVec;
@@ -59,24 +50,14 @@ use rustc_span::{ExpnId, ExpnKind, Span};
 use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
 pub use rustc_target::abi::{ReprFlags, ReprOptions};
 pub use rustc_type_ir::relate::VarianceDiagInfo;
-use tracing::{debug, instrument};
-pub use vtable::*;
-
-use std::assert_matches::assert_matches;
-use std::fmt::Debug;
-use std::hash::{Hash, Hasher};
-use std::marker::PhantomData;
-use std::mem;
-use std::num::NonZero;
-use std::ptr::NonNull;
-use std::{fmt, str};
-
-pub use crate::ty::diagnostics::*;
 pub use rustc_type_ir::ConstKind::{
     Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt,
     Placeholder as PlaceholderCt, Unevaluated, Value,
 };
 pub use rustc_type_ir::*;
+use tracing::{debug, instrument};
+pub use vtable::*;
+use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
 
 pub use self::closure::{
     analyze_coroutine_closure_captures, is_ancestor_or_same_capture, place_to_string_for_capture,
@@ -91,6 +72,7 @@ pub use self::context::{
     tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift,
     TyCtxt, TyCtxtFeed,
 };
+pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams};
 pub use self::list::{List, ListWithCachedTypeInfo};
 pub use self::opaque_types::OpaqueTypeKey;
@@ -105,9 +87,9 @@ pub use self::predicate::{
     PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
     TraitPredicate, TraitRef, TypeOutlivesPredicate,
 };
+pub use self::region::BoundRegionKind::*;
 pub use self::region::{
-    BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region,
-    RegionKind, RegionVid,
+    BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, Region, RegionKind, RegionVid,
 };
 pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::{
@@ -120,6 +102,20 @@ pub use self::typeck_results::{
     CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
     TypeckResults, UserType, UserTypeAnnotationIndex,
 };
+pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+pub use self::AssocItemContainer::*;
+pub use self::BorrowKind::*;
+pub use self::IntVarValue::*;
+use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
+use crate::metadata::ModChild;
+use crate::middle::privacy::EffectiveVisibilities;
+use crate::mir::{Body, CoroutineLayout};
+use crate::query::Providers;
+use crate::traits::{self, Reveal};
+use crate::ty;
+pub use crate::ty::diagnostics::*;
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::util::Discr;
 
 pub mod abstract_const;
 pub mod adjustment;
@@ -266,6 +262,7 @@ pub struct ImplTraitHeader<'tcx> {
     pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
     pub polarity: ImplPolarity,
     pub safety: hir::Safety,
+    pub do_not_recommend: bool,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
@@ -2148,8 +2145,9 @@ pub struct DestructuredConst<'tcx> {
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(PredicateKind<'_>, 32);
     static_assert_size!(WithCachedTypeInfo<TyKind<'_>>, 56);
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 96f00e1d306..e51d2201922 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -7,11 +7,12 @@
 //! `normalize_generic_arg_after_erasing_regions` query for each type
 //! or constant found within. (This underlying query is what is cached.)
 
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
+use tracing::{debug, instrument};
+
 use crate::traits::query::NoSolution;
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
 use crate::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
-use rustc_macros::{HashStable, TyDecodable, TyEncodable};
-use tracing::{debug, instrument};
 
 #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
 pub enum NormalizationError<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 70a54e96d36..d3f44326c27 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -1,12 +1,12 @@
-use crate::error::ConstNotUsedTraitAlias;
-use crate::ty::fold::{TypeFolder, TypeSuperFoldable};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
-use crate::ty::{GenericArg, GenericArgKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use tracing::{debug, instrument, trace};
 
+use crate::error::ConstNotUsedTraitAlias;
+use crate::ty::fold::{TypeFolder, TypeSuperFoldable};
+use crate::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
+
 pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey<TyCtxt<'tcx>>;
 
 /// Converts generic params of a TypeFoldable from one
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index f394b3c990c..7e1255f606c 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -1,7 +1,8 @@
+use std::hash::Hash;
+
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def_id::DefIndex;
 use rustc_index::{Idx, IndexVec};
-use std::hash::Hash;
 
 use crate::ty;
 
diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs
index d1875fbaea3..e604aedd05e 100644
--- a/compiler/rustc_middle/src/ty/pattern.rs
+++ b/compiler/rustc_middle/src/ty/pattern.rs
@@ -1,9 +1,10 @@
 use std::fmt;
 
-use crate::ty;
 use rustc_data_structures::intern::Interned;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
+use crate::ty;
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
 #[rustc_pass_by_value]
 pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 5d6352c57ce..8e72505b862 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -1,9 +1,10 @@
+use std::cmp::Ordering;
+
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::DefId;
 use rustc_macros::{extension, HashStable};
 use rustc_type_ir as ir;
-use std::cmp::Ordering;
 use tracing::instrument;
 
 use crate::ty::{
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index c165790548d..6cce79dfdc1 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -1,8 +1,5 @@
 use std::path::PathBuf;
 
-use crate::ty::GenericArg;
-use crate::ty::{self, ShortInstance, Ty, TyCtxt};
-
 use hir::def::Namespace;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
@@ -11,10 +8,11 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use tracing::{debug, instrument, trace};
 
+use crate::ty::{self, GenericArg, ShortInstance, Ty, TyCtxt};
+
 // `pretty` is a separate module only for organization.
 mod pretty;
 pub use self::pretty::*;
-
 use super::Lift;
 
 pub type PrintError = std::fmt::Error;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 0e241663e18..29d72183dd3 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,11 +1,8 @@
-use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
-use crate::query::IntoQueryParam;
-use crate::query::Providers;
-use crate::ty::GenericArgKind;
-use crate::ty::{
-    ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
-};
+use std::cell::Cell;
+use std::fmt::{self, Write as _};
+use std::iter;
+use std::ops::{Deref, DerefMut};
+
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_apfloat::Float;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -25,13 +22,14 @@ use rustc_target::spec::abi::Abi;
 use rustc_type_ir::{elaborate, Upcast as _};
 use smallvec::SmallVec;
 
-use std::cell::Cell;
-use std::fmt::{self, Write as _};
-use std::iter;
-use std::ops::{Deref, DerefMut};
-
 // `pretty` is a separate module only for organization.
 use super::*;
+use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
+use crate::query::{IntoQueryParam, Providers};
+use crate::ty::{
+    ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TypeFoldable,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+};
 
 macro_rules! p {
     (@$lit:literal) => {
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 4e85af90170..a2a96105777 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -1,13 +1,13 @@
+use std::ops::Deref;
+
 use rustc_data_structures::intern::Interned;
 use rustc_errors::MultiSpan;
 use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
-use rustc_span::symbol::sym;
-use rustc_span::symbol::{kw, Symbol};
+use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use rustc_type_ir::RegionKind as IrRegionKind;
 pub use rustc_type_ir::RegionVid;
-use std::ops::Deref;
 use tracing::debug;
 
 use crate::ty::{self, BoundVar, TyCtxt, TypeFlags};
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index 8ec7946e718..bcab54cf8ba 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -1,9 +1,10 @@
-use crate::middle::region::{Scope, ScopeData, ScopeTree};
 use rustc_hir as hir;
 use rustc_hir::ItemLocalMap;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use tracing::debug;
 
+use crate::middle::region::{Scope, ScopeData, ScopeTree};
+
 /// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
 /// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`.
 #[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7cdc0e32953..8fb44a5f0b1 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -3,11 +3,8 @@
 //! written by hand, though we've recently added some macros and proc-macros
 //! to help with the tedium.
 
-use crate::mir::interpret;
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
-use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
-use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
+use std::fmt::{self, Debug};
+
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_hir::def::Namespace;
@@ -15,12 +12,13 @@ use rustc_span::source_map::Spanned;
 use rustc_target::abi::TyAndLayout;
 use rustc_type_ir::ConstKind;
 
-use std::fmt::{self, Debug};
-
 use super::print::PrettyPrinter;
-use super::{GenericArg, GenericArgKind, Region};
-
-use super::Pattern;
+use super::{GenericArg, GenericArgKind, Pattern, Region};
+use crate::mir::interpret;
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
+use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 
 impl fmt::Debug for ty::TraitDef {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index da98e3b9f46..8781a670acb 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2,14 +2,11 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
-use crate::infer::canonical::Canonical;
-use crate::ty::InferTy::*;
-use crate::ty::{
-    self, AdtDef, BoundRegionKind, Discr, Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable,
-    TypeVisitable, TypeVisitor,
-};
-use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
-use crate::ty::{List, ParamEnv};
+use std::assert_matches::debug_assert_matches;
+use std::borrow::Cow;
+use std::iter;
+use std::ops::{ControlFlow, Range};
+
 use hir::def::{CtorKind, DefKind};
 use rustc_data_structures::captures::Captures;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
@@ -22,16 +19,17 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 use rustc_target::spec::abi;
 use rustc_type_ir::visit::TypeVisitableExt;
-use std::assert_matches::debug_assert_matches;
-use std::borrow::Cow;
-use std::iter;
-use std::ops::{ControlFlow, Range};
-use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
-
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
+use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
 
 use super::GenericParamDefKind;
+use crate::infer::canonical::Canonical;
+use crate::ty::InferTy::*;
+use crate::ty::{
+    self, AdtDef, BoundRegionKind, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv,
+    Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+};
 
 // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
 #[rustc_diagnostic_item = "TyKind"]
@@ -1592,7 +1590,7 @@ impl<'tcx> Ty<'tcx> {
         tcx: TyCtxt<'tcx>,
         normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
     ) -> Result<Ty<'tcx>, Ty<'tcx>> {
-        let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
+        let tail = tcx.struct_tail_raw(self, normalize, || {});
         match tail.kind() {
             // Sized types
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -1616,10 +1614,10 @@ impl<'tcx> Ty<'tcx> {
             | ty::Foreign(..)
             // `dyn*` has metadata = ().
             | ty::Dynamic(_, _, ty::DynStar)
-            // If returned by `struct_tail_with_normalize` this is a unit struct
+            // If returned by `struct_tail_raw` this is a unit struct
             // without any fields, or not a struct, and therefore is Sized.
             | ty::Adt(..)
-            // If returned by `struct_tail_with_normalize` this is the empty tuple,
+            // If returned by `struct_tail_raw` this is the empty tuple,
             // a.k.a. unit type, which is Sized
             | ty::Tuple(..) => Ok(tcx.types.unit),
 
@@ -1966,8 +1964,9 @@ impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(ty::RegionKind<'_>, 24);
     static_assert_size!(ty::TyKind<'_>, 32);
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 3bd9f6ad11b..dfb137f738f 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,13 +1,12 @@
 use std::iter;
-use tracing::debug;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_macros::{Decodable, Encodable, HashStable};
+use tracing::debug;
 
 use crate::query::LocalCrate;
 use crate::traits::specialization_graph;
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index a6dec66449e..a92bdb2eae0 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -1,21 +1,15 @@
-use crate::{
-    hir::place::Place as HirPlace,
-    infer::canonical::Canonical,
-    traits::ObligationCause,
-    ty::{
-        self, tls, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind,
-        GenericArgs, GenericArgsRef, Ty, UserArgs,
-    },
-};
+use std::collections::hash_map::Entry;
+use std::hash::Hash;
+use std::iter;
+
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
+use rustc_hir::hir_id::OwnerId;
 use rustc_hir::{
-    self as hir,
-    def::{DefKind, Res},
-    def_id::{DefId, LocalDefId, LocalDefIdMap},
-    hir_id::OwnerId,
-    BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
+    self as hir, BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
 };
 use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
@@ -23,9 +17,15 @@ use rustc_middle::mir::FakeReadCause;
 use rustc_session::Session;
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
-use std::{collections::hash_map::Entry, hash::Hash, iter};
 
 use super::RvalueScopes;
+use crate::hir::place::Place as HirPlace;
+use crate::infer::canonical::Canonical;
+use crate::traits::ObligationCause;
+use crate::ty::{
+    self, tls, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs,
+    GenericArgsRef, Ty, UserArgs,
+};
 
 #[derive(TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct TypeckResults<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4335d96737a..6be3dc423de 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1,13 +1,7 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
-use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::query::{IntoQueryParam, Providers};
-use crate::ty::layout::{FloatExt, IntegerExt};
-use crate::ty::{
-    self, Asyncness, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt, Upcast,
-};
-use crate::ty::{GenericArgKind, GenericArgsRef};
+use std::{fmt, iter};
+
 use rustc_apfloat::Float as _;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
@@ -23,9 +17,16 @@ use rustc_span::sym;
 use rustc_target::abi::{Float, Integer, IntegerType, Size};
 use rustc_target::spec::abi::Abi;
 use smallvec::{smallvec, SmallVec};
-use std::{fmt, iter};
 use tracing::{debug, instrument, trace};
 
+use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::query::{IntoQueryParam, Providers};
+use crate::ty::layout::{FloatExt, IntegerExt};
+use crate::ty::{
+    self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
+    TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
+};
+
 #[derive(Copy, Clone, Debug)]
 pub struct Discr<'tcx> {
     /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
@@ -78,7 +79,7 @@ impl<'tcx> Discr<'tcx> {
         let (val, oflo) = if signed {
             let min = size.signed_int_min();
             let max = size.signed_int_max();
-            let val = size.sign_extend(self.val) as i128;
+            let val = size.sign_extend(self.val);
             assert!(n < (i128::MAX as u128));
             let n = n as i128;
             let oflo = val > max - n;
@@ -170,14 +171,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Attempts to returns the deeply last field of nested structures, but
-    /// does not apply any normalization in its search. Returns the same type
-    /// if input `ty` is not a structure at all.
-    pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let tcx = self;
-        tcx.struct_tail_with_normalize(ty, |ty| ty, || {})
-    }
-
     /// Returns the deeply last field of nested structures, or the same type if
     /// not a structure at all. Corresponds to the only possible unsized field,
     /// and its type can be used to determine unsizing strategy.
@@ -185,13 +178,9 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Should only be called if `ty` has no inference variables and does not
     /// need its lifetimes preserved (e.g. as part of codegen); otherwise
     /// normalization attempt may cause compiler bugs.
-    pub fn struct_tail_erasing_lifetimes(
-        self,
-        ty: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Ty<'tcx> {
+    pub fn struct_tail_for_codegen(self, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
         let tcx = self;
-        tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
+        tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
     }
 
     /// Returns the deeply last field of nested structures, or the same type if
@@ -199,12 +188,14 @@ impl<'tcx> TyCtxt<'tcx> {
     /// and its type can be used to determine unsizing strategy.
     ///
     /// This is parameterized over the normalization strategy (i.e. how to
-    /// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
-    /// function to indicate no normalization should take place.
+    /// handle `<T as Trait>::Assoc` and `impl Trait`). You almost certainly do
+    /// **NOT** want to pass the identity function here, unless you know what
+    /// you're doing, or you're within normalization code itself and will handle
+    /// an unnormalized tail recursively.
     ///
-    /// See also `struct_tail_erasing_lifetimes`, which is suitable for use
+    /// See also `struct_tail_for_codegen`, which is suitable for use
     /// during codegen.
-    pub fn struct_tail_with_normalize(
+    pub fn struct_tail_raw(
         self,
         mut ty: Ty<'tcx>,
         mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
@@ -271,20 +262,20 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Same as applying `struct_tail` on `source` and `target`, but only
     /// keeps going as long as the two types are instances of the same
     /// structure definitions.
-    /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
+    /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, dyn Trait)`,
     /// whereas struct_tail produces `T`, and `Trait`, respectively.
     ///
     /// Should only be called if the types have no inference variables and do
     /// not need their lifetimes preserved (e.g., as part of codegen); otherwise,
     /// normalization attempt may cause compiler bugs.
-    pub fn struct_lockstep_tails_erasing_lifetimes(
+    pub fn struct_lockstep_tails_for_codegen(
         self,
         source: Ty<'tcx>,
         target: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> (Ty<'tcx>, Ty<'tcx>) {
         let tcx = self;
-        tcx.struct_lockstep_tails_with_normalize(source, target, |ty| {
+        tcx.struct_lockstep_tails_raw(source, target, |ty| {
             tcx.normalize_erasing_regions(param_env, ty)
         })
     }
@@ -295,9 +286,9 @@ impl<'tcx> TyCtxt<'tcx> {
     /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
     /// whereas struct_tail produces `T`, and `Trait`, respectively.
     ///
-    /// See also `struct_lockstep_tails_erasing_lifetimes`, which is suitable for use
+    /// See also `struct_lockstep_tails_for_codegen`, which is suitable for use
     /// during codegen.
-    pub fn struct_lockstep_tails_with_normalize(
+    pub fn struct_lockstep_tails_raw(
         self,
         source: Ty<'tcx>,
         target: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index b1bbfd420e1..78d83004c14 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -1,11 +1,11 @@
-use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
+use std::ops::ControlFlow;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_type_ir::fold::TypeFoldable;
-use std::ops::ControlFlow;
-
 pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 
+use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
+
 ///////////////////////////////////////////////////////////////////////////
 // Region folder
 
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 466c3b93f8e..951112dfe85 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -1,10 +1,11 @@
 use std::fmt;
 
-use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar};
-use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
 use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 
+use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, CTFE_ALLOC_SALT};
+use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
+
 #[derive(Clone, Copy, PartialEq, HashStable)]
 pub enum VtblEntry<'tcx> {
     /// destructor of this type (used in vtable header)
@@ -72,6 +73,11 @@ pub(crate) fn vtable_min_entries<'tcx>(
 
 /// Retrieves an allocation that represents the contents of a vtable.
 /// Since this is a query, allocations are cached and not duplicated.
+///
+/// This is an "internal" `AllocId` that should never be used as a value in the interpreted program.
+/// The interpreter should use `AllocId` that refer to a `GlobalAlloc::VTable` instead.
+/// (This is similar to statics, which also have a similar "internal" `AllocId` storing their
+/// initial contents.)
 pub(super) fn vtable_allocation_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
@@ -113,7 +119,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
             VtblEntry::MetadataDropInPlace => {
                 if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
                     let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
-                    let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
+                    let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
                     let fn_ptr = Pointer::from(fn_alloc_id);
                     Scalar::from_pointer(fn_ptr, &tcx)
                 } else {
@@ -126,7 +132,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
             VtblEntry::Method(instance) => {
                 // Prepare the fn ptr we write into the vtable.
                 let instance = instance.polymorphize(tcx);
-                let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
+                let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
                 let fn_ptr = Pointer::from(fn_alloc_id);
                 Scalar::from_pointer(fn_ptr, &tcx)
             }
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index efcaf89081f..2dd7a96f192 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -1,12 +1,12 @@
 //! An iterator over the type substructure.
 //! WARNING: this does not keep track of the region depth.
 
-use crate::ty::{self, Ty};
-use crate::ty::{GenericArg, GenericArgKind};
 use rustc_data_structures::sso::SsoHashSet;
 use smallvec::{smallvec, SmallVec};
 use tracing::debug;
 
+use crate::ty::{self, GenericArg, GenericArgKind, Ty};
+
 // The TypeWalker's stack is hot enough that it's worth going to some effort to
 // avoid heap allocations.
 type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index 43853a10896..32f5251568f 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -1,11 +1,13 @@
 // These functions are used by macro expansion for bug! and span_bug!
 
-use crate::ty::{tls, TyCtxt};
-use rustc_errors::MultiSpan;
-use rustc_span::Span;
 use std::fmt;
 use std::panic::{panic_any, Location};
 
+use rustc_errors::MultiSpan;
+use rustc_span::Span;
+
+use crate::ty::{tls, TyCtxt};
+
 #[cold]
 #[inline(never)]
 #[track_caller]
diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs
index 0815c291173..75ae4e11fa9 100644
--- a/compiler/rustc_middle/src/util/call_kind.rs
+++ b/compiler/rustc_middle/src/util/call_kind.rs
@@ -2,14 +2,14 @@
 //! as well as errors when attempting to call a non-const function in a const
 //! context.
 
-use crate::ty::GenericArgsRef;
-use crate::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{lang_items, LangItem};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, DesugaringKind, Span};
 use tracing::debug;
 
+use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, ParamEnv, Ty, TyCtxt};
+
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum CallDesugaringKind {
     /// for _ in x {} calls x.into_iter()
diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs
index 831853b0b48..ec6051d0a77 100644
--- a/compiler/rustc_middle/src/util/find_self_call.rs
+++ b/compiler/rustc_middle/src/util/find_self_call.rs
@@ -1,10 +1,10 @@
-use crate::mir::*;
-use crate::ty::GenericArgsRef;
-use crate::ty::{self, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::Spanned;
 use tracing::debug;
 
+use crate::mir::*;
+use crate::ty::{self, GenericArgsRef, TyCtxt};
+
 /// Checks if the specified `local` is used as the `self` parameter of a method call
 /// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
 /// returned.
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 8c323188826..9e429f5a4c7 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -1,19 +1,20 @@
-use crate::dep_graph::dep_kinds;
-use crate::query::plumbing::CyclePlaceholder;
+use std::collections::VecDeque;
+use std::fmt::Write;
+use std::ops::ControlFlow;
+
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan};
+use rustc_errors::codes::*;
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_middle::ty::Representability;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
 use rustc_query_system::query::{report_cycle, CycleError};
 use rustc_query_system::Value;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{ErrorGuaranteed, Span};
 
-use std::collections::VecDeque;
-use std::fmt::Write;
-use std::ops::ControlFlow;
+use crate::dep_graph::dep_kinds;
+use crate::query::plumbing::CyclePlaceholder;
 
 impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index c608e5c63d8..7afa628843f 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -1,13 +1,14 @@
-use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops};
-use crate::build::ForGuard::OutsideGuard;
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use rustc_middle::middle::region::Scope;
-use rustc_middle::span_bug;
+use rustc_middle::mir::*;
 use rustc_middle::thir::*;
-use rustc_middle::{mir::*, ty};
+use rustc_middle::{span_bug, ty};
 use rustc_span::Span;
 use tracing::debug;
 
+use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops};
+use crate::build::ForGuard::OutsideGuard;
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn ast_block(
         &mut self,
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index 6034c8fadc5..e80b654309e 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -1,10 +1,11 @@
 //! Routines for manipulating the control-flow graph.
 
-use crate::build::CFG;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use tracing::debug;
 
+use crate::build::CFG;
+
 impl<'tcx> CFG<'tcx> {
     pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
         &self.basic_blocks[blk]
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index f6ebcbcbdc9..28477e527c7 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -22,12 +22,10 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
 use rustc_index::{IndexSlice, IndexVec};
-use rustc_middle::{
-    mir::*,
-    span_bug,
-    thir::*,
-    ty::{ParamEnv, Ty, TyCtxt},
-};
+use rustc_middle::mir::*;
+use rustc_middle::span_bug;
+use rustc_middle::thir::*;
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::Span;
 
 mod parse;
@@ -56,8 +54,8 @@ pub(super) fn build_custom_mir<'tcx>(
         spread_arg: None,
         var_debug_info: Vec::new(),
         span,
-        required_consts: Vec::new(),
-        mentioned_items: Vec::new(),
+        required_consts: None,
+        mentioned_items: None,
         is_polymorphic: false,
         tainted_by_errors: None,
         injection_phase: None,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index 9607022c6df..646aefa0882 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -1,6 +1,7 @@
 use rustc_index::IndexSlice;
+use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, Ty};
-use rustc_middle::{mir::*, thir::*};
 use rustc_span::Span;
 
 use super::{PResult, ParseCtxt, ParseError};
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 94ab2fb4581..56896d945e5 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -1,16 +1,17 @@
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::mir::*;
+use rustc_middle::thir::*;
+use rustc_middle::ty;
 use rustc_middle::ty::cast::mir_cast_kind;
-use rustc_middle::{mir::*, thir::*, ty};
 use rustc_span::source_map::Spanned;
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 
+use super::{parse_by_kind, PResult, ParseCtxt};
 use crate::build::custom::ParseError;
 use crate::build::expr::as_constant::as_constant_inner;
 
-use super::{parse_by_kind, PResult, ParseCtxt};
-
 impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
         parse_by_kind!(self, expr_id, _, "statement",
@@ -74,6 +75,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             @call(mir_call, args) => {
                 self.parse_call(args)
             },
+            @call(mir_tail_call, args) => {
+                self.parse_tail_call(args)
+            },
             ExprKind::Match { scrutinee, arms, .. } => {
                 let discr = self.parse_operand(*scrutinee)?;
                 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
@@ -186,6 +190,25 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         )
     }
 
+    fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, args[0], _, "tail call",
+            ExprKind::Call { fun, args, fn_span, .. } => {
+                let fun = self.parse_operand(*fun)?;
+                let args = args
+                    .iter()
+                    .map(|arg|
+                        Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span  } )
+                    )
+                    .collect::<PResult<Box<[_]>>>()?;
+                Ok(TerminatorKind::TailCall {
+                    func: fun,
+                    args,
+                    fn_span: *fn_span,
+                })
+            },
+        )
+    }
+
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, expr, "rvalue",
             @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index be62a3d3736..4430aab73a8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -1,19 +1,21 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::{parse_float_into_constval, Builder};
 use rustc_ast as ast;
 use rustc_hir::LangItem;
-use rustc_middle::mir;
-use rustc_middle::mir::interpret::{Allocation, LitToConstError, LitToConstInput, Scalar};
+use rustc_middle::mir::interpret::{
+    Allocation, LitToConstError, LitToConstInput, Scalar, CTFE_ALLOC_SALT,
+};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{
     self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex,
 };
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_target::abi::Size;
 use tracing::{instrument, trace};
 
+use crate::build::{parse_float_into_constval, Builder};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
@@ -140,7 +142,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_dedup(data);
+            let id = tcx.allocate_bytes_dedup(data, CTFE_ALLOC_SALT);
             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/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 09ce134a2bf..1e67e759aa2 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -1,12 +1,13 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::expr::category::Category;
-use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use tracing::{debug, instrument};
 
+use crate::build::expr::category::Category;
+use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Returns an operand suitable for use until the end of the current
     /// scope expression.
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 91a3b53cc79..b80d9de70c8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -1,24 +1,23 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::expr::category::Category;
-use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
-use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap};
+use std::assert_matches::assert_matches;
+use std::iter;
+
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::hir::place::Projection as HirProjection;
-use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
+use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind};
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
-use rustc_middle::ty::AdtDef;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance};
+use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 use tracing::{debug, instrument, trace};
 
-use std::assert_matches::assert_matches;
-use std::iter;
+use crate::build::expr::category::Category;
+use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap};
 
 /// The "outermost" place that holds this value.
 #[derive(Copy, Clone, Debug, PartialEq)]
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 40cfe563acc..379d2140c09 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -1,14 +1,7 @@
 //! See docs in `build/expr/mod.rs`.
 
-use rustc_index::{Idx, IndexVec};
-use rustc_middle::ty::util::IntTypeExt;
-use rustc_span::source_map::Spanned;
-use rustc_target::abi::{Abi, FieldIdx, Primitive};
-
-use crate::build::expr::as_place::PlaceBase;
-use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 use rustc_hir::lang_items::LangItem;
+use rustc_index::{Idx, IndexVec};
 use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Scalar;
@@ -16,10 +9,17 @@ use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
 use rustc_middle::ty::layout::IntegerExt;
+use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, Ty, UpvarArgs};
+use rustc_span::source_map::Spanned;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::{Abi, FieldIdx, Primitive};
 use tracing::debug;
 
+use crate::build::expr::as_place::PlaceBase;
+use crate::build::expr::category::{Category, RvalueFunc};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Returns an rvalue suitable for use until the end of the current
     /// scope expression.
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 82673582e79..af5940ff50e 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -1,13 +1,14 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::scope::DropKind;
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use tracing::{debug, instrument};
 
+use crate::build::scope::DropKind;
+use crate::build::{BlockAnd, BlockAndExtension, Builder};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr` into a fresh temporary. This is used when building
     /// up rvalues so as to freeze the value that will be consumed.
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 9cd958a21da..01b32b8e05e 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -1,8 +1,7 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::matches::DeclareLetBindings;
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
+use std::iter;
+
 use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -12,9 +11,12 @@ use rustc_middle::span_bug;
 use rustc_middle::thir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use rustc_span::source_map::Spanned;
-use std::iter;
 use tracing::{debug, instrument};
 
+use crate::build::expr::category::{Category, RvalueFunc};
+use crate::build::matches::DeclareLetBindings;
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 8e13edb4c89..b38f0a41e5d 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -1,5 +1,3 @@
-use crate::build::scope::BreakableTarget;
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
@@ -7,6 +5,9 @@ use rustc_middle::thir::*;
 use rustc_span::source_map::Spanned;
 use tracing::debug;
 
+use crate::build::scope::BreakableTarget;
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Builds a block of MIR statements to evaluate the THIR `expr`.
     ///
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 95fec154918..ab2bfcbca3a 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -208,14 +208,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 subpairs = cx.field_match_pairs(downcast_place, subpatterns);
 
                 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        (cx.tcx.features().exhaustive_patterns
-                            || cx.tcx.features().min_exhaustive_patterns)
-                            && !v
-                                .inhabited_predicate(cx.tcx, adt_def)
-                                .instantiate(cx.tcx, args)
-                                .apply_ignore_module(cx.tcx, cx.param_env)
-                    }
+                    i == variant_index
+                        || !v
+                            .inhabited_predicate(cx.tcx, adt_def)
+                            .instantiate(cx.tcx, args)
+                            .apply_ignore_module(cx.tcx, cx.param_env)
                 }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 6ac8f0d0023..cae4aa7bad3 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -5,12 +5,8 @@
 //! This also includes code for pattern bindings in `let` statements and
 //! function parameters.
 
-use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::scope::DropKind;
-use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
-use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack};
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::{BindingMode, ByRef};
 use rustc_middle::bug;
 use rustc_middle::middle::region;
@@ -21,7 +17,13 @@ use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, Pos, Span};
 use rustc_target::abi::VariantIdx;
 use tracing::{debug, instrument};
-use util::visit_bindings;
+
+use crate::build::expr::as_place::PlaceBuilder;
+use crate::build::scope::DropKind;
+use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
+use crate::build::{
+    BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode,
+};
 
 // helper functions, broken out by category:
 mod match_pair;
@@ -363,28 +365,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let scrutinee_place =
             unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span));
 
-        let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms);
-
-        let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
-        let mut candidates =
-            arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
-
+        let arms = arms.iter().map(|arm| &self.thir[*arm]);
         let match_start_span = span.shrink_to_lo().to(scrutinee_span);
-
-        // The set of places that we are creating fake borrows of. If there are no match guards then
-        // we don't need any fake borrows, so don't track them.
-        let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard {
-            util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base())
-        } else {
-            Vec::new()
-        };
-
-        self.lower_match_tree(
+        let patterns = arms
+            .clone()
+            .map(|arm| {
+                let has_match_guard =
+                    if arm.guard.is_some() { HasMatchGuard::Yes } else { HasMatchGuard::No };
+                (&*arm.pattern, has_match_guard)
+            })
+            .collect();
+        let built_tree = self.lower_match_tree(
             block,
             scrutinee_span,
             &scrutinee_place,
             match_start_span,
-            &mut candidates,
+            patterns,
             false,
         );
 
@@ -392,9 +388,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             destination,
             scrutinee_place,
             scrutinee_span,
-            arm_candidates,
+            arms,
+            built_tree,
             self.source_info(span),
-            fake_borrow_temps,
         )
     }
 
@@ -414,51 +410,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block.and(scrutinee_place_builder)
     }
 
-    /// Create the initial `Candidate`s for a `match` expression.
-    fn create_match_candidates<'pat>(
-        &mut self,
-        scrutinee: &PlaceBuilder<'tcx>,
-        arms: &'pat [ArmId],
-    ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)>
-    where
-        'a: 'pat,
-    {
-        // Assemble the initial list of candidates. These top-level candidates
-        // are 1:1 with the original match arms, but other parts of match
-        // lowering also introduce subcandidates (for subpatterns), and will
-        // also flatten candidates in some cases. So in general a list of
-        // candidates does _not_ necessarily correspond to a list of arms.
-        arms.iter()
-            .copied()
-            .map(|arm| {
-                let arm = &self.thir[arm];
-                let arm_has_guard = arm.guard.is_some();
-                let arm_candidate =
-                    Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard, self);
-                (arm, arm_candidate)
-            })
-            .collect()
-    }
-
     /// Lower the bindings, guards and arm bodies of a `match` expression.
     ///
     /// The decision tree should have already been created
     /// (by [Builder::lower_match_tree]).
     ///
     /// `outer_source_info` is the SourceInfo for the whole match.
-    fn lower_match_arms(
+    fn lower_match_arms<'pat>(
         &mut self,
         destination: Place<'tcx>,
         scrutinee_place_builder: PlaceBuilder<'tcx>,
         scrutinee_span: Span,
-        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
+        arms: impl IntoIterator<Item = &'pat Arm<'tcx>>,
+        built_match_tree: BuiltMatchTree<'tcx>,
         outer_source_info: SourceInfo,
-        fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
-    ) -> BlockAnd<()> {
-        let arm_end_blocks: Vec<BasicBlock> = arm_candidates
+    ) -> BlockAnd<()>
+    where
+        'tcx: 'pat,
+    {
+        let arm_end_blocks: Vec<BasicBlock> = arms
             .into_iter()
-            .map(|(arm, candidate)| {
-                debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
+            .zip(built_match_tree.branches)
+            .map(|(arm, branch)| {
+                debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch);
 
                 let arm_source_info = self.source_info(arm.span);
                 let arm_scope = (arm.scope, arm_source_info);
@@ -491,8 +465,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     let arm_block = this.bind_pattern(
                         outer_source_info,
-                        candidate,
-                        &fake_borrow_temps,
+                        branch,
+                        &built_match_tree.fake_borrow_temps,
                         scrutinee_span,
                         Some((arm, match_scope)),
                         EmitStorageLive::Yes,
@@ -545,18 +519,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn bind_pattern(
         &mut self,
         outer_source_info: SourceInfo,
-        candidate: Candidate<'_, 'tcx>,
+        branch: MatchTreeBranch<'tcx>,
         fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)],
         scrutinee_span: Span,
         arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
         emit_storage_live: EmitStorageLive,
     ) -> BasicBlock {
-        if candidate.subcandidates.is_empty() {
-            // Avoid generating another `BasicBlock` when we only have one
-            // candidate.
+        if branch.sub_branches.len() == 1 {
+            let [sub_branch] = branch.sub_branches.try_into().unwrap();
+            // Avoid generating another `BasicBlock` when we only have one sub branch.
             self.bind_and_guard_matched_candidate(
-                candidate,
-                &[],
+                sub_branch,
                 fake_borrow_temps,
                 scrutinee_span,
                 arm_match_scope,
@@ -584,35 +557,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // We keep a stack of all of the bindings and type ascriptions
             // from the parent candidates that we visit, that also need to
             // be bound for each candidate.
-            traverse_candidate(
-                candidate,
-                &mut Vec::new(),
-                &mut |leaf_candidate, parent_data| {
-                    if let Some(arm) = arm {
-                        self.clear_top_scope(arm.scope);
-                    }
-                    let binding_end = self.bind_and_guard_matched_candidate(
-                        leaf_candidate,
-                        parent_data,
-                        fake_borrow_temps,
-                        scrutinee_span,
-                        arm_match_scope,
-                        schedule_drops,
-                        emit_storage_live,
-                    );
-                    if arm.is_none() {
-                        schedule_drops = ScheduleDrops::No;
-                    }
-                    self.cfg.goto(binding_end, outer_source_info, target_block);
-                },
-                |inner_candidate, parent_data| {
-                    parent_data.push(inner_candidate.extra_data);
-                    inner_candidate.subcandidates.into_iter()
-                },
-                |parent_data| {
-                    parent_data.pop();
-                },
-            );
+            for sub_branch in branch.sub_branches {
+                if let Some(arm) = arm {
+                    self.clear_top_scope(arm.scope);
+                }
+                let binding_end = self.bind_and_guard_matched_candidate(
+                    sub_branch,
+                    fake_borrow_temps,
+                    scrutinee_span,
+                    arm_match_scope,
+                    schedule_drops,
+                    emit_storage_live,
+                );
+                if arm.is_none() {
+                    schedule_drops = ScheduleDrops::No;
+                }
+                self.cfg.goto(binding_end, outer_source_info, target_block);
+            }
 
             target_block
         }
@@ -722,7 +683,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         initializer: PlaceBuilder<'tcx>,
         set_match_place: bool,
     ) -> BlockAnd<()> {
-        let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self);
+        let built_tree = self.lower_match_tree(
+            block,
+            irrefutable_pat.span,
+            &initializer,
+            irrefutable_pat.span,
+            vec![(irrefutable_pat, HasMatchGuard::No)],
+            false,
+        );
+        let [branch] = built_tree.branches.try_into().unwrap();
 
         // For matches and function arguments, the place that is being matched
         // can be set when creating the variables. But the place for
@@ -743,7 +712,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // };
             // ```
             if let Some(place) = initializer.try_to_place(self) {
-                visit_bindings(&[&mut candidate], |binding: &Binding<'_>| {
+                // Because or-alternatives bind the same variables, we only explore the first one.
+                let first_sub_branch = branch.sub_branches.first().unwrap();
+                for binding in &first_sub_branch.bindings {
                     let local = self.var_local_id(binding.var_id, OutsideGuard);
                     if let LocalInfo::User(BindingForm::Var(VarBindingForm {
                         opt_match_place: Some((ref mut match_place, _)),
@@ -754,21 +725,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     } else {
                         bug!("Let binding to non-user variable.")
                     };
-                });
+                }
             }
         }
 
-        self.lower_match_tree(
-            block,
-            irrefutable_pat.span,
-            &initializer,
-            irrefutable_pat.span,
-            &mut [&mut candidate],
-            false,
-        );
         self.bind_pattern(
             self.source_info(irrefutable_pat.span),
-            candidate,
+            branch,
             &[],
             irrefutable_pat.span,
             None,
@@ -1149,20 +1112,21 @@ struct Candidate<'pat, 'tcx> {
     /// The earliest block that has only candidates >= this one as descendents. Used for false
     /// edges, see the doc for [`Builder::match_expr`].
     false_edge_start_block: Option<BasicBlock>,
-    /// The `false_edge_start_block` of the next candidate.
-    next_candidate_start_block: Option<BasicBlock>,
 }
 
 impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
     fn new(
         place: PlaceBuilder<'tcx>,
         pattern: &'pat Pat<'tcx>,
-        has_guard: bool,
+        has_guard: HasMatchGuard,
         cx: &mut Builder<'_, 'tcx>,
     ) -> Self {
         // Use `FlatPat` to build simplified match pairs, then immediately
         // incorporate them into a new candidate.
-        Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard)
+        Self::from_flat_pat(
+            FlatPat::new(place, pattern, cx),
+            matches!(has_guard, HasMatchGuard::Yes),
+        )
     }
 
     /// Incorporates an already-simplified [`FlatPat`] into a new candidate.
@@ -1176,7 +1140,6 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
             otherwise_block: None,
             pre_binding_block: None,
             false_edge_start_block: None,
-            next_candidate_start_block: None,
         }
     }
 
@@ -1196,6 +1159,17 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
             |_| {},
         );
     }
+
+    /// Visit the leaf candidates in reverse order.
+    fn visit_leaves_rev<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) {
+        traverse_candidate(
+            self,
+            &mut (),
+            &mut move |c, _| visit_leaf(c),
+            move |c, _| c.subcandidates.iter_mut().rev(),
+            |_| {},
+        );
+    }
 }
 
 /// A depth-first traversal of the `Candidate` and all of its recursive
@@ -1406,12 +1380,114 @@ pub(crate) struct ArmHasGuard(pub(crate) bool);
 ///////////////////////////////////////////////////////////////////////////
 // Main matching algorithm
 
+/// A sub-branch in the output of match lowering. Match lowering has generated MIR code that will
+/// branch to `success_block` when the matched value matches the corresponding pattern. If there is
+/// a guard, its failure must continue to `otherwise_block`, which will resume testing patterns.
+#[derive(Debug)]
+struct MatchTreeSubBranch<'tcx> {
+    span: Span,
+    /// The block that is branched to if the corresponding subpattern matches.
+    success_block: BasicBlock,
+    /// The block to branch to if this arm had a guard and the guard fails.
+    otherwise_block: BasicBlock,
+    /// The bindings to set up in this sub-branch.
+    bindings: Vec<Binding<'tcx>>,
+    /// The ascriptions to set up in this sub-branch.
+    ascriptions: Vec<Ascription<'tcx>>,
+    /// Whether the sub-branch corresponds to a never pattern.
+    is_never: bool,
+}
+
+/// A branch in the output of match lowering.
+#[derive(Debug)]
+struct MatchTreeBranch<'tcx> {
+    sub_branches: Vec<MatchTreeSubBranch<'tcx>>,
+}
+
+/// The result of generating MIR for a pattern-matching expression. Each input branch/arm/pattern
+/// gives rise to an output `MatchTreeBranch`. If one of the patterns matches, we branch to the
+/// corresponding `success_block`. If none of the patterns matches, we branch to `otherwise_block`.
+///
+/// Each branch is made of one of more sub-branches, corresponding to or-patterns. E.g.
+/// ```ignore(illustrative)
+/// match foo {
+///     (x, false) | (false, x) => {}
+///     (true, true) => {}
+/// }
+/// ```
+/// Here the first arm gives the first `MatchTreeBranch`, which has two sub-branches, one for each
+/// alternative of the or-pattern. They are kept separate because each needs to bind `x` to a
+/// different place.
+#[derive(Debug)]
+struct BuiltMatchTree<'tcx> {
+    branches: Vec<MatchTreeBranch<'tcx>>,
+    otherwise_block: BasicBlock,
+    /// If any of the branches had a guard, we collect here the places and locals to fakely borrow
+    /// to ensure match guards can't modify the values as we match them. For more details, see
+    /// [`util::collect_fake_borrows`].
+    fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
+}
+
+impl<'tcx> MatchTreeSubBranch<'tcx> {
+    fn from_sub_candidate(
+        candidate: Candidate<'_, 'tcx>,
+        parent_data: &Vec<PatternExtraData<'tcx>>,
+    ) -> Self {
+        debug_assert!(candidate.match_pairs.is_empty());
+        MatchTreeSubBranch {
+            span: candidate.extra_data.span,
+            success_block: candidate.pre_binding_block.unwrap(),
+            otherwise_block: candidate.otherwise_block.unwrap(),
+            bindings: parent_data
+                .iter()
+                .flat_map(|d| &d.bindings)
+                .chain(&candidate.extra_data.bindings)
+                .cloned()
+                .collect(),
+            ascriptions: parent_data
+                .iter()
+                .flat_map(|d| &d.ascriptions)
+                .cloned()
+                .chain(candidate.extra_data.ascriptions)
+                .collect(),
+            is_never: candidate.extra_data.is_never,
+        }
+    }
+}
+
+impl<'tcx> MatchTreeBranch<'tcx> {
+    fn from_candidate(candidate: Candidate<'_, 'tcx>) -> Self {
+        let mut sub_branches = Vec::new();
+        traverse_candidate(
+            candidate,
+            &mut Vec::new(),
+            &mut |candidate: Candidate<'_, '_>, parent_data: &mut Vec<PatternExtraData<'_>>| {
+                sub_branches.push(MatchTreeSubBranch::from_sub_candidate(candidate, parent_data));
+            },
+            |inner_candidate, parent_data| {
+                parent_data.push(inner_candidate.extra_data);
+                inner_candidate.subcandidates.into_iter()
+            },
+            |parent_data| {
+                parent_data.pop();
+            },
+        );
+        MatchTreeBranch { sub_branches }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum HasMatchGuard {
+    Yes,
+    No,
+}
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// The entrypoint of the matching algorithm. Create the decision tree for the match expression,
     /// starting from `block`.
     ///
-    /// Modifies `candidates` to store the bindings and type ascriptions for
-    /// that candidate.
+    /// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether
+    /// the arm has a guard.
     ///
     /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
     /// or not (for `let` and `match`). In the refutable case we return the block to which we branch
@@ -1422,31 +1498,76 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         scrutinee_span: Span,
         scrutinee_place_builder: &PlaceBuilder<'tcx>,
         match_start_span: Span,
-        candidates: &mut [&mut Candidate<'pat, 'tcx>],
+        patterns: Vec<(&'pat Pat<'tcx>, HasMatchGuard)>,
         refutable: bool,
-    ) -> BasicBlock {
+    ) -> BuiltMatchTree<'tcx>
+    where
+        'tcx: 'pat,
+    {
+        // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
+        // input patterns, but other parts of match lowering also introduce subcandidates (for
+        // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
+        // match arms directly.
+        let mut candidates: Vec<Candidate<'_, '_>> = patterns
+            .into_iter()
+            .map(|(pat, has_guard)| {
+                Candidate::new(scrutinee_place_builder.clone(), pat, has_guard, self)
+            })
+            .collect();
+
+        let fake_borrow_temps = util::collect_fake_borrows(
+            self,
+            &candidates,
+            scrutinee_span,
+            scrutinee_place_builder.base(),
+        );
+
         // 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.
+        // If none of the arms match, we branch to `otherwise_block`. When lowering a `match`
+        // expression, exhaustiveness checking ensures that this block is unreachable.
+        let mut candidate_refs = candidates.iter_mut().collect::<Vec<_>>();
         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;
-        for candidate in candidates {
-            candidate.visit_leaves(|leaf_candidate| {
-                if let Some(ref mut prev) = previous_candidate {
-                    assert!(leaf_candidate.false_edge_start_block.is_some());
-                    prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
+            self.match_candidates(match_start_span, scrutinee_span, block, &mut candidate_refs);
+
+        // Set up false edges so that the borrow-checker cannot make use of the specific CFG we
+        // generated. We falsely branch from each candidate to the one below it to make it as if we
+        // were testing match branches one by one in order. In the refutable case we also want a
+        // false edge to the final failure block.
+        let mut next_candidate_start_block = if refutable { Some(otherwise_block) } else { None };
+        for candidate in candidates.iter_mut().rev() {
+            let has_guard = candidate.has_guard;
+            candidate.visit_leaves_rev(|leaf_candidate| {
+                if let Some(next_candidate_start_block) = next_candidate_start_block {
+                    let source_info = self.source_info(leaf_candidate.extra_data.span);
+                    // Falsely branch to `next_candidate_start_block` before reaching pre_binding.
+                    let old_pre_binding = leaf_candidate.pre_binding_block.unwrap();
+                    let new_pre_binding = self.cfg.start_new_block();
+                    self.false_edges(
+                        old_pre_binding,
+                        new_pre_binding,
+                        next_candidate_start_block,
+                        source_info,
+                    );
+                    leaf_candidate.pre_binding_block = Some(new_pre_binding);
+                    if has_guard {
+                        // Falsely branch to `next_candidate_start_block` also if the guard fails.
+                        let new_otherwise = self.cfg.start_new_block();
+                        let old_otherwise = leaf_candidate.otherwise_block.unwrap();
+                        self.false_edges(
+                            new_otherwise,
+                            old_otherwise,
+                            next_candidate_start_block,
+                            source_info,
+                        );
+                        leaf_candidate.otherwise_block = Some(new_otherwise);
+                    }
                 }
-                previous_candidate = Some(leaf_candidate);
+                assert!(leaf_candidate.false_edge_start_block.is_some());
+                next_candidate_start_block = leaf_candidate.false_edge_start_block;
             });
         }
 
-        if refutable {
-            // In refutable cases there's always at least one candidate, and we want a false edge to
-            // the failure block.
-            previous_candidate.as_mut().unwrap().next_candidate_start_block = Some(otherwise_block)
-        } else {
+        if !refutable {
             // Match checking ensures `otherwise_block` is actually unreachable in irrefutable
             // cases.
             let source_info = self.source_info(scrutinee_span);
@@ -1476,7 +1597,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable);
         }
 
-        otherwise_block
+        BuiltMatchTree {
+            branches: candidates.into_iter().map(MatchTreeBranch::from_candidate).collect(),
+            otherwise_block,
+            fake_borrow_temps,
+        }
     }
 
     /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
@@ -2226,17 +2351,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) -> BlockAnd<()> {
         let expr_span = self.thir[expr_id].span;
         let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span));
-        let mut candidate = Candidate::new(scrutinee.clone(), pat, false, self);
-        let otherwise_block = self.lower_match_tree(
+        let built_tree = self.lower_match_tree(
             block,
             expr_span,
             &scrutinee,
             pat.span,
-            &mut [&mut candidate],
+            vec![(pat, HasMatchGuard::No)],
             true,
         );
+        let [branch] = built_tree.branches.try_into().unwrap();
 
-        self.break_for_else(otherwise_block, self.source_info(expr_span));
+        self.break_for_else(built_tree.otherwise_block, self.source_info(expr_span));
 
         match declare_let_bindings {
             DeclareLetBindings::Yes => {
@@ -2258,7 +2383,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let success = self.bind_pattern(
             self.source_info(pat.span),
-            candidate,
+            branch,
             &[],
             expr_span,
             None,
@@ -2266,7 +2391,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         );
 
         // If branch coverage is enabled, record this branch.
-        self.visit_coverage_conditional_let(pat, success, otherwise_block);
+        self.visit_coverage_conditional_let(pat, success, built_tree.otherwise_block);
 
         success.unit()
     }
@@ -2279,52 +2404,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Note: we do not check earlier that if there is a guard,
     /// there cannot be move bindings. We avoid a use-after-move by only
     /// moving the binding once the guard has evaluated to true (see below).
-    fn bind_and_guard_matched_candidate<'pat>(
+    fn bind_and_guard_matched_candidate(
         &mut self,
-        candidate: Candidate<'pat, 'tcx>,
-        parent_data: &[PatternExtraData<'tcx>],
+        sub_branch: MatchTreeSubBranch<'tcx>,
         fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)],
         scrutinee_span: Span,
         arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
         schedule_drops: ScheduleDrops,
         emit_storage_live: EmitStorageLive,
     ) -> BasicBlock {
-        debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
-
-        debug_assert!(candidate.match_pairs.is_empty());
+        debug!("bind_and_guard_matched_candidate(subbranch={:?})", sub_branch);
 
-        let candidate_source_info = self.source_info(candidate.extra_data.span);
+        let block = sub_branch.success_block;
 
-        let mut block = candidate.pre_binding_block.unwrap();
-
-        if candidate.next_candidate_start_block.is_some() {
-            let fresh_block = self.cfg.start_new_block();
-            self.false_edges(
-                block,
-                fresh_block,
-                candidate.next_candidate_start_block,
-                candidate_source_info,
-            );
-            block = fresh_block;
-        }
-
-        if candidate.extra_data.is_never {
+        if sub_branch.is_never {
             // This arm has a dummy body, we don't need to generate code for it. `block` is already
             // unreachable (except via false edge).
-            let source_info = self.source_info(candidate.extra_data.span);
+            let source_info = self.source_info(sub_branch.span);
             self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
             return self.cfg.start_new_block();
         }
 
-        let ascriptions = parent_data
-            .iter()
-            .flat_map(|d| &d.ascriptions)
-            .cloned()
-            .chain(candidate.extra_data.ascriptions);
-        let bindings =
-            parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings);
-
-        self.ascribe_types(block, ascriptions);
+        self.ascribe_types(block, sub_branch.ascriptions);
 
         // Lower an instance of the arm guard (if present) for this candidate,
         // and then perform bindings for the arm body.
@@ -2335,9 +2436,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             // Bindings for guards require some extra handling to automatically
             // insert implicit references/dereferences.
-            self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
+            self.bind_matched_candidate_for_guard(
+                block,
+                schedule_drops,
+                sub_branch.bindings.iter(),
+            );
             let guard_frame = GuardFrame {
-                locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(),
+                locals: sub_branch
+                    .bindings
+                    .iter()
+                    .map(|b| GuardFrameLocal::new(b.var_id))
+                    .collect(),
             };
             debug!("entering guard building context: {:?}", guard_frame);
             self.guard_context.push(guard_frame);
@@ -2373,17 +2482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
             }
 
-            let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| {
-                let unreachable = self.cfg.start_new_block();
-                self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
-                unreachable
-            });
-            self.false_edges(
-                otherwise_post_guard_block,
-                otherwise_block,
-                candidate.next_candidate_start_block,
-                source_info,
-            );
+            self.cfg.goto(otherwise_post_guard_block, source_info, sub_branch.otherwise_block);
 
             // We want to ensure that the matched candidates are bound
             // after we have confirmed this candidate *and* any
@@ -2411,8 +2510,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // ```
             //
             // and that is clearly not correct.
-            let by_value_bindings =
-                bindings.filter(|binding| matches!(binding.binding_mode.0, ByRef::No));
+            let by_value_bindings = sub_branch
+                .bindings
+                .iter()
+                .filter(|binding| matches!(binding.binding_mode.0, ByRef::No));
             // Read all of the by reference bindings to ensure that the
             // place they refer to can't be modified by the guard.
             for binding in by_value_bindings.clone() {
@@ -2440,7 +2541,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.bind_matched_candidate_for_arm_body(
                 block,
                 schedule_drops,
-                bindings,
+                sub_branch.bindings.iter(),
                 emit_storage_live,
             );
             block
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 20310f60821..04cf81d54e9 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -12,11 +12,12 @@
 //! sort of test: for example, testing which variant an enum is, or
 //! testing a value against a constant.
 
-use crate::build::matches::{MatchPairTree, PatternExtraData, TestCase};
-use crate::build::Builder;
+use std::mem;
+
 use tracing::{debug, instrument};
 
-use std::mem;
+use crate::build::matches::{MatchPairTree, PatternExtraData, TestCase};
+use crate::build::Builder;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 802193b8ddf..7af1ede24a4 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -5,14 +5,14 @@
 // identify what tests are needed, perform the tests, and then filter
 // the candidates based on the result.
 
-use crate::build::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind};
-use crate::build::Builder;
+use std::cmp::Ordering;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::{LangItem, RangeEnd};
 use rustc_middle::mir::*;
+use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::Spanned;
@@ -20,7 +20,8 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use tracing::{debug, instrument};
 
-use std::cmp::Ordering;
+use crate::build::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind};
+use crate::build::Builder;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Identifies what test is needed to decide if `match_pair` is applicable.
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 8fe8069b345..8491b5fe380 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,14 +1,13 @@
-use std::marker::PhantomData;
-
-use crate::build::expr::as_place::PlaceBase;
-use crate::build::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase};
-use crate::build::Builder;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::*;
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
 use tracing::debug;
 
+use crate::build::expr::as_place::PlaceBase;
+use crate::build::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase};
+use crate::build::Builder;
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// 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
@@ -17,18 +16,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         from_block: BasicBlock,
         real_target: BasicBlock,
-        imaginary_target: Option<BasicBlock>,
+        imaginary_target: BasicBlock,
         source_info: SourceInfo,
     ) {
-        match imaginary_target {
-            Some(target) if target != real_target => {
-                self.cfg.terminate(
-                    from_block,
-                    source_info,
-                    TerminatorKind::FalseEdge { real_target, imaginary_target: target },
-                );
-            }
-            _ => self.cfg.goto(from_block, source_info, real_target),
+        if imaginary_target != real_target {
+            self.cfg.terminate(
+                from_block,
+                source_info,
+                TerminatorKind::FalseEdge { real_target, imaginary_target },
+            );
+        } else {
+            self.cfg.goto(from_block, source_info, real_target)
         }
     }
 }
@@ -70,10 +68,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 ///    a MIR pass run after borrow checking.
 pub(super) fn collect_fake_borrows<'tcx>(
     cx: &mut Builder<'_, 'tcx>,
-    candidates: &[&mut Candidate<'_, 'tcx>],
+    candidates: &[Candidate<'_, 'tcx>],
     temp_span: Span,
     scrutinee_base: PlaceBase,
 ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
+    if candidates.iter().all(|candidate| !candidate.has_guard) {
+        // Fake borrows are only used when there is a guard.
+        return Vec::new();
+    }
     let mut collector =
         FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap::default() };
     for candidate in candidates.iter() {
@@ -221,57 +223,6 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
     }
 }
 
-/// Visit all the bindings of these candidates. Because or-alternatives bind the same variables, we
-/// only explore the first one of each or-pattern.
-pub(super) fn visit_bindings<'tcx>(
-    candidates: &[&mut Candidate<'_, 'tcx>],
-    f: impl FnMut(&Binding<'tcx>),
-) {
-    let mut visitor = BindingsVisitor { f, phantom: PhantomData };
-    for candidate in candidates.iter() {
-        visitor.visit_candidate(candidate);
-    }
-}
-
-pub(super) struct BindingsVisitor<'tcx, F> {
-    f: F,
-    phantom: PhantomData<&'tcx ()>,
-}
-
-impl<'tcx, F> BindingsVisitor<'tcx, F>
-where
-    F: FnMut(&Binding<'tcx>),
-{
-    fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
-        for binding in &candidate.extra_data.bindings {
-            (self.f)(binding)
-        }
-        for match_pair in &candidate.match_pairs {
-            self.visit_match_pair(match_pair);
-        }
-    }
-
-    fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) {
-        for binding in &flat_pat.extra_data.bindings {
-            (self.f)(binding)
-        }
-        for match_pair in &flat_pat.match_pairs {
-            self.visit_match_pair(match_pair);
-        }
-    }
-
-    fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) {
-        if let TestCase::Or { pats, .. } = &match_pair.test_case {
-            // All the or-alternatives should bind the same locals, so we only visit the first one.
-            self.visit_flat_pat(&pats[0])
-        } else {
-            for subpair in &match_pair.subpairs {
-                self.visit_match_pair(subpair);
-            }
-        }
-    }
-}
-
 #[must_use]
 pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind {
     match ref_mutability {
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index 04e6d24e5a1..26906973ca8 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -1,14 +1,14 @@
 //! Miscellaneous builder routines that are not specific to building any particular
 //! kind of thing.
 
-use crate::build::Builder;
-
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::debug;
 
+use crate::build::Builder;
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Adds a new temporary value of type `ty` storing the result of
     /// evaluating `expr`.
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 2793a7d8736..b98deda8fd0 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1,5 +1,3 @@
-use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::scope::DropKind;
 use itertools::Itertools;
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_apfloat::Float;
@@ -21,12 +19,13 @@ use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, Pa
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
-use rustc_span::Span;
-use rustc_span::Symbol;
+use rustc_span::{Span, Symbol};
 use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi::Abi;
 
 use super::lints;
+use crate::build::expr::as_place::PlaceBuilder;
+use crate::build::scope::DropKind;
 
 pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index b630c74a202..8546a2539d7 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -83,7 +83,6 @@ that contains only loops and breakable blocks. It tracks where a `break`,
 
 use std::mem;
 
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::HirId;
 use rustc_index::{IndexSlice, IndexVec};
@@ -96,6 +95,8 @@ use rustc_span::source_map::Spanned;
 use rustc_span::{Span, DUMMY_SP};
 use tracing::{debug, instrument};
 
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
+
 #[derive(Debug)]
 pub(crate) struct Scopes<'tcx> {
     scopes: Vec<Scope>,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 6309f2ac98e..54a4204da71 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,9 +1,11 @@
-use crate::build::ExprCategory;
-use crate::errors::*;
+use std::borrow::Cow;
+use std::mem;
+use std::ops::Bound;
 
 use rustc_errors::DiagArgValue;
 use rustc_hir::def::DefKind;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::span_bug;
 use rustc_middle::thir::visit::Visitor;
@@ -16,9 +18,8 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 
-use std::borrow::Cow;
-use std::mem;
-use std::ops::Bound;
+use crate::build::ExprCategory;
+use crate::errors::*;
 
 struct UnsafetyVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
     safety_context: SafetyContext,
     /// The `#[target_feature]` attributes of the body. Used for checking
     /// calls to functions with `#[target_feature]` (RFC 2396).
-    body_target_features: &'tcx [Symbol],
+    body_target_features: &'tcx [TargetFeature],
     /// When inside the LHS of an assignment to a field, this is the type
     /// of the LHS and the span of the assignment expression.
     assignment_info: Option<Ty<'tcx>>,
@@ -442,14 +443,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     // is_like_wasm check in hir_analysis/src/collect.rs
                     let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
                     if !self.tcx.sess.target.options.is_like_wasm
-                        && !callee_features
-                            .iter()
-                            .all(|feature| self.body_target_features.contains(feature))
+                        && !callee_features.iter().all(|feature| {
+                            self.body_target_features.iter().any(|f| f.name == feature.name)
+                        })
                     {
                         let missing: Vec<_> = callee_features
                             .iter()
                             .copied()
-                            .filter(|feature| !self.body_target_features.contains(feature))
+                            .filter(|feature| {
+                                !feature.implied
+                                    && !self
+                                        .body_target_features
+                                        .iter()
+                                        .any(|body_feature| body_feature.name == feature.name)
+                            })
+                            .map(|feature| feature.name)
                             .collect();
                         let build_enabled = self
                             .tcx
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index bdc4b0ea97d..42eca71ca3f 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,15 +1,17 @@
-use crate::fluent_generated as fluent;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level, MultiSpan,
-    SubdiagMessageOp, Subdiagnostic,
+    Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
+    MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
-use rustc_errors::{DiagArgValue, DiagCtxtHandle};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
-use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcPatCtxt};
+use rustc_pattern_analysis::errors::Uncovered;
+use rustc_pattern_analysis::rustc::RustcPatCtxt;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use crate::fluent_generated as fluent;
+
 #[derive(LintDiagnostic)]
 #[diag(mir_build_unconditional_recursion)]
 #[help]
@@ -856,7 +858,7 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     pub(crate) span: Span,
     pub(crate) origin: &'s str,
     #[subdiagnostic]
-    pub(crate) uncovered: Uncovered<'tcx>,
+    pub(crate) uncovered: Uncovered,
     #[subdiagnostic]
     pub(crate) inform: Option<Inform>,
     #[subdiagnostic]
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 263e777d03a..80e91811b1c 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -1,14 +1,15 @@
-use crate::errors::UnconditionalRecursion;
+use std::ops::ControlFlow;
+
 use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
 use rustc_hir::def::DefKind;
 use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArg, GenericArgs};
+use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt};
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
-use std::ops::ControlFlow;
+
+use crate::errors::UnconditionalRecursion;
 
 pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     check_call_recursion(tcx, body);
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 95cd703dbb3..069c2e7881e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -1,5 +1,3 @@
-use crate::thir::cx::Cx;
-
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_middle::middle::region;
@@ -8,6 +6,8 @@ use rustc_middle::ty;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use tracing::debug;
 
+use crate::thir::cx::Cx;
+
 impl<'tcx> Cx<'tcx> {
     pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> BlockId {
         // We have to eagerly lower the "spine" of the statements
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 5f13b329de4..d4de5fac96e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1,30 +1,31 @@
-use crate::errors;
-use crate::thir::cx::region::Scope;
-use crate::thir::cx::Cx;
-use crate::thir::util::UserAnnotatedTyHelpers;
 use itertools::Itertools;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_index::Idx;
-use rustc_middle::hir::place::Place as HirPlace;
-use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
-use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
+use rustc_middle::hir::place::{
+    Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
+};
 use rustc_middle::middle::region;
 use rustc_middle::mir::{self, BinOp, BorrowKind, UnOp};
 use rustc_middle::thir::*;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion,
 };
-use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{
-    self, AdtKind, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs, UserType,
+    self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs,
+    UserType,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, Span};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use tracing::{debug, info, instrument, trace};
 
+use crate::errors;
+use crate::thir::cx::region::Scope;
+use crate::thir::cx::Cx;
+use crate::thir::util::UserAnnotatedTyHelpers;
+
 impl<'tcx> Cx<'tcx> {
     pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 244ac409fd3..6120b1453cf 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -2,23 +2,22 @@
 //! structures into the THIR. The `builder` is generally ignorant of the tcx,
 //! etc., and instead goes through the `Cx` for most of its work.
 
-use crate::thir::pattern::pat_from_hir;
-use crate::thir::util::UserAnnotatedTyHelpers;
-
 use rustc_data_structures::steal::Steal;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::HirId;
-use rustc_hir::Node;
+use rustc_hir::{HirId, Node};
 use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
 use tracing::instrument;
 
+use crate::thir::pattern::pat_from_hir;
+use crate::thir::util::UserAnnotatedTyHelpers;
+
 pub(crate) fn thir_body(
     tcx: TyCtxt<'_>,
     owner_def: LocalDefId,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 5e904057e73..07bf222fcca 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,11 +1,9 @@
-use crate::errors::*;
-use crate::fluent_generated as fluent;
-
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
@@ -27,6 +25,9 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::{sym, Span};
 use tracing::instrument;
 
+use crate::errors::*;
+use crate::fluent_generated as fluent;
+
 pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
     let typeck_results = tcx.typeck(def_id);
     let (thir, expr) = tcx.thir_body(def_id)?;
@@ -482,9 +483,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         // Check if the match is exhaustive.
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
-            if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 {
+            if source == hir::MatchSource::ForLoopDesugar
+                && let [_, snd_arm] = *arms
+            {
                 // the for loop pattern is not irrefutable
-                let pat = &self.thir[arms[1]].pattern;
+                let pat = &self.thir[snd_arm].pattern;
                 // `pat` should be `Some(<pat_field>)` from a desugared for loop.
                 debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop));
                 let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() };
@@ -694,9 +697,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
 
         // Emit an extra note if the first uncovered witness would be uninhabited
         // if we disregard visibility.
-        let witness_1_is_privately_uninhabited = if (self.tcx.features().exhaustive_patterns
-            || self.tcx.features().min_exhaustive_patterns)
-            && let Some(witness_1) = witnesses.get(0)
+        let witness_1_is_privately_uninhabited = if let Some(witness_1) = witnesses.get(0)
             && let ty::Adt(adt, args) = witness_1.ty().kind()
             && adt.is_enum()
             && let Constructor::Variant(variant_index) = witness_1.ctor()
@@ -1058,7 +1059,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
                 err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary");
             } else if cx.is_foreign_non_exhaustive_enum(ty) {
                 err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
-            } else if cx.is_uninhabited(ty.inner()) && cx.tcx.features().min_exhaustive_patterns {
+            } else if cx.is_uninhabited(ty.inner()) {
                 // The type is uninhabited yet there is a witness: we must be in the `MaybeInvalid`
                 // case.
                 err.note(format!("`{ty}` is uninhabited but is not being matched by value, so a wildcard `_` is required"));
@@ -1077,7 +1078,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     let suggested_arm = if suggest_the_witnesses {
         let pattern = witnesses
             .iter()
-            .map(|witness| cx.hoist_witness_pat(witness).to_string())
+            .map(|witness| cx.print_witness_pat(witness))
             .collect::<Vec<String>>()
             .join(" | ");
         if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns {
@@ -1195,13 +1196,13 @@ fn joined_uncovered_patterns<'p, 'tcx>(
     witnesses: &[WitnessPat<'p, 'tcx>],
 ) -> String {
     const LIMIT: usize = 3;
-    let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.hoist_witness_pat(pat).to_string();
+    let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.print_witness_pat(pat);
     match witnesses {
         [] => bug!(),
-        [witness] => format!("`{}`", cx.hoist_witness_pat(witness)),
+        [witness] => format!("`{}`", cx.print_witness_pat(witness)),
         [head @ .., tail] if head.len() < LIMIT => {
             let head: Vec<_> = head.iter().map(pat_to_str).collect();
-            format!("`{}` and `{}`", head.join("`, `"), cx.hoist_witness_pat(tail))
+            format!("`{}` and `{}`", head.join("`, `"), cx.print_witness_pat(tail))
         }
         _ => {
             let (head, tail) = witnesses.split_at(LIMIT);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 0d54f332585..6f8d17b772a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -7,8 +7,7 @@ use rustc_infer::traits::Obligation;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 622651800f4..615070034b9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -3,10 +3,7 @@
 mod check_match;
 mod const_to_pat;
 
-pub(crate) use self::check_match::check_match;
-
-use crate::errors::*;
-use crate::thir::util::UserAnnotatedTyHelpers;
+use std::cmp::Ordering;
 
 use rustc_errors::codes::*;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -26,7 +23,9 @@ use rustc_span::{ErrorGuaranteed, Span};
 use rustc_target::abi::{FieldIdx, Integer};
 use tracing::{debug, instrument};
 
-use std::cmp::Ordering;
+pub(crate) use self::check_match::check_match;
+use crate::errors::*;
+use crate::thir::util::UserAnnotatedTyHelpers;
 
 struct PatCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 619bfbcf43d..2d4b39e7b08 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -1,8 +1,9 @@
+use std::fmt::{self, Write};
+
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::thir::*;
 use rustc_middle::ty;
 use rustc_span::def_id::LocalDefId;
-use std::fmt::{self, Write};
 
 pub(crate) fn thir_tree(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String {
     match super::cx::thir_body(*tcx, owner_def) {
diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index 82c59d7d959..bb53eaf6cbd 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -1,10 +1,9 @@
-use crate::elaborate_drops::DropFlagState;
 use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
 use rustc_target::abi::VariantIdx;
 use tracing::debug;
 
 use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
-use super::MoveDataParamEnv;
+use crate::elaborate_drops::DropFlagState;
 
 pub fn move_path_children_matching<'tcx, F>(
     move_data: &MoveData<'tcx>,
@@ -70,12 +69,11 @@ pub fn on_all_children_bits<'tcx, F>(
 
 pub fn drop_flag_effects_for_function_entry<'tcx, F>(
     body: &Body<'tcx>,
-    ctxt: &MoveDataParamEnv<'tcx>,
+    move_data: &MoveData<'tcx>,
     mut callback: F,
 ) where
     F: FnMut(MovePathIndex, DropFlagState),
 {
-    let move_data = &ctxt.move_data;
     for arg in body.args_iter() {
         let place = mir::Place::from(arg);
         let lookup_result = move_data.rev_lookup.find(place.as_ref());
@@ -87,13 +85,12 @@ pub fn drop_flag_effects_for_function_entry<'tcx, F>(
 
 pub fn drop_flag_effects_for_location<'tcx, F>(
     body: &Body<'tcx>,
-    ctxt: &MoveDataParamEnv<'tcx>,
+    move_data: &MoveData<'tcx>,
     loc: Location,
     mut callback: F,
 ) where
     F: FnMut(MovePathIndex, DropFlagState),
 {
-    let move_data = &ctxt.move_data;
     debug!("drop_flag_effects_for_location({:?})", loc);
 
     // first, move out of the RHS
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index e0da9600ae3..2ec3b53bc98 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -1,3 +1,5 @@
+use std::{fmt, iter};
+
 use rustc_hir::lang_items::LangItem;
 use rustc_index::Idx;
 use rustc_middle::mir::patch::MirPatch;
@@ -5,12 +7,10 @@ use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
 use rustc_span::source_map::Spanned;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
-use std::{fmt, iter};
 use tracing::{debug, instrument};
 
 /// The value of an inserted drop flag.
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index 1bd9167be12..7cfaef22689 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -1,7 +1,5 @@
 //! Random access inspection of the results of a dataflow analysis.
 
-use crate::framework::BitSetExt;
-
 use std::cmp::Ordering;
 
 #[cfg(debug_assertions)]
@@ -9,6 +7,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, BasicBlock, Location};
 
 use super::{Analysis, Direction, Effect, EffectIndex, Results};
+use crate::framework::BitSetExt;
 
 /// Allows random access inspection of the results of a dataflow analysis.
 ///
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index f57e8b8bd6f..ba4a7d76511 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -1,7 +1,8 @@
+use std::ops::RangeInclusive;
+
 use rustc_middle::mir::{
     self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
 };
-use std::ops::RangeInclusive;
 
 use super::visitor::{ResultsVisitable, ResultsVisitor};
 use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 564a99e5df8..364a416480f 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -1,32 +1,28 @@
 //! A solver for dataflow problems.
 
-use crate::errors::{
-    DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
-};
-use crate::framework::BitSetExt;
-
 use std::ffi::OsString;
 use std::path::PathBuf;
 
-use rustc_ast as ast;
 use rustc_data_structures::work_queue::WorkQueue;
-use rustc_graphviz as dot;
 use rustc_hir::def_id::DefId;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::bug;
-use rustc_middle::mir::{self, traversal, BasicBlock};
-use rustc_middle::mir::{create_dump_file, dump_enabled};
+use rustc_middle::mir::{self, create_dump_file, dump_enabled, traversal, BasicBlock};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 use tracing::{debug, error};
+use {rustc_ast as ast, rustc_graphviz as dot};
 
 use super::fmt::DebugWithContext;
-use super::graphviz;
 use super::{
-    visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet,
-    JoinSemiLattice, ResultsCursor, ResultsVisitor,
+    graphviz, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis,
+    GenKillSet, JoinSemiLattice, ResultsCursor, ResultsVisitor,
 };
+use crate::errors::{
+    DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
+};
+use crate::framework::BitSetExt;
 
 pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
index e3a66bd952c..5e4f36e4ae3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
@@ -1,10 +1,12 @@
 //! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow
 //! analysis.
 
-use super::lattice::MaybeReachable;
+use std::fmt;
+
 use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
 use rustc_index::Idx;
-use std::fmt;
+
+use super::lattice::MaybeReachable;
 
 /// An extension to `fmt::Debug` for data that can be better printed with some auxiliary data `C`.
 pub trait DebugWithContext<C>: Eq + fmt::Debug {
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index a827f6a8dbd..2e860e2d841 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -8,8 +8,7 @@ use std::{io, ops, str};
 use regex::Regex;
 use rustc_graphviz as dot;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::graphviz_safe_def_name;
-use rustc_middle::mir::{self, BasicBlock, Body, Location};
+use rustc_middle::mir::{self, graphviz_safe_def_name, BasicBlock, Body, Location};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
 use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor};
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 23738f7a4a5..4d03ee53b7c 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -38,10 +38,12 @@
 //! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
 //! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
 
-use crate::framework::BitSetExt;
+use std::iter;
+
 use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
 use rustc_index::{Idx, IndexVec};
-use std::iter;
+
+use crate::framework::BitSetExt;
 
 /// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements
 /// in the set.
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index d44da42416d..7822fb17f72 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -1,3 +1,5 @@
+use std::assert_matches::assert_matches;
+
 use rustc_index::bit_set::{BitSet, ChunkedBitSet};
 use rustc_index::Idx;
 use rustc_middle::bug;
@@ -5,15 +7,14 @@ use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}
 use rustc_middle::ty::{self, TyCtxt};
 use tracing::{debug, instrument};
 
-use crate::drop_flag_effects_for_function_entry;
-use crate::drop_flag_effects_for_location;
 use crate::elaborate_drops::DropFlagState;
 use crate::framework::SwitchIntEdgeEffects;
 use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
-use crate::on_lookup_result_bits;
-use crate::MoveDataParamEnv;
-use crate::{drop_flag_effects, on_all_children_bits};
-use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable};
+use crate::{
+    drop_flag_effects, drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
+    lattice, on_all_children_bits, on_lookup_result_bits, AnalysisDomain, GenKill, GenKillAnalysis,
+    MaybeReachable,
+};
 
 /// `MaybeInitializedPlaces` tracks all places that might be
 /// initialized upon reaching a particular point in the control flow
@@ -53,17 +54,13 @@ use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable};
 pub struct MaybeInitializedPlaces<'a, 'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'mir Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
     skip_unreachable_unwind: bool,
 }
 
 impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir Body<'tcx>,
-        mdpe: &'a MoveDataParamEnv<'tcx>,
-    ) -> Self {
-        MaybeInitializedPlaces { tcx, body, mdpe, skip_unreachable_unwind: false }
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
+        MaybeInitializedPlaces { tcx, body, move_data, skip_unreachable_unwind: false }
     }
 
     pub fn skipping_unreachable_unwind(mut self) -> Self {
@@ -90,7 +87,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> {
 
 impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -132,22 +129,18 @@ impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx
 pub struct MaybeUninitializedPlaces<'a, 'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'mir Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
 
     mark_inactive_variants_as_uninit: bool,
     skip_unreachable_unwind: BitSet<mir::BasicBlock>,
 }
 
 impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir Body<'tcx>,
-        mdpe: &'a MoveDataParamEnv<'tcx>,
-    ) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
         MaybeUninitializedPlaces {
             tcx,
             body,
-            mdpe,
+            move_data,
             mark_inactive_variants_as_uninit: false,
             skip_unreachable_unwind: BitSet::new_empty(body.basic_blocks.len()),
         }
@@ -174,7 +167,7 @@ impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> {
 
 impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, '_, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -214,18 +207,18 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, '_, 'tcx> {
 /// that would require a dynamic drop-flag at that statement.
 pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
     body: &'a Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
 }
 
 impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
-    pub fn new(body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        DefinitelyInitializedPlaces { body, mdpe }
+    pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
+        DefinitelyInitializedPlaces { body, move_data }
     }
 }
 
 impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -260,18 +253,18 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
 /// ```
 pub struct EverInitializedPlaces<'a, 'mir, 'tcx> {
     body: &'mir Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
 }
 
 impl<'a, 'mir, 'tcx> EverInitializedPlaces<'a, 'mir, 'tcx> {
-    pub fn new(body: &'mir Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        EverInitializedPlaces { body, mdpe }
+    pub fn new(body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
+        EverInitializedPlaces { body, move_data }
     }
 }
 
 impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, '_, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -329,7 +322,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         *state =
             MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len()));
-        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
             assert!(s == DropFlagState::Present);
             state.gen_(path);
         });
@@ -349,7 +342,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
 
@@ -381,7 +374,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
         {
             edges = TerminatorEdges::Single(target);
         }
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(state, path, s)
         });
         edges
@@ -466,7 +459,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
         // set all bits to 1 (uninit) before gathering counter-evidence
         state.insert_all();
 
-        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
             assert!(s == DropFlagState::Present);
             state.remove(path);
         });
@@ -486,7 +479,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
 
@@ -500,12 +493,12 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
         if self.skip_unreachable_unwind.contains(location.block) {
             let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() };
-            assert!(matches!(unwind, mir::UnwindAction::Cleanup(_)));
+            assert_matches!(unwind, mir::UnwindAction::Cleanup(_));
             TerminatorEdges::Single(target)
         } else {
             terminator.edges()
@@ -593,7 +586,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         state.0.clear();
 
-        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
             assert!(s == DropFlagState::Present);
             state.0.insert(path);
         });
@@ -613,7 +606,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
@@ -624,7 +617,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
         terminator.edges()
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index f8db18fc1f8..f283660e1e7 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -7,13 +7,12 @@ mod initialized;
 mod liveness;
 mod storage_liveness;
 
-pub use self::borrowed_locals::borrowed_locals;
-pub use self::borrowed_locals::MaybeBorrowedLocals;
+pub use self::borrowed_locals::{borrowed_locals, MaybeBorrowedLocals};
 pub use self::initialized::{
     DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces,
     MaybeUninitializedPlaces,
 };
-pub use self::liveness::MaybeLiveLocals;
-pub use self::liveness::MaybeTransitiveLiveLocals;
-pub use self::liveness::TransferFunction as LivenessTransferFunction;
+pub use self::liveness::{
+    MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
+};
 pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive};
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 682cec12f1f..9f2f0187698 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,9 +1,9 @@
+use std::borrow::Cow;
+
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 
-use std::borrow::Cow;
-
 use super::MaybeBorrowedLocals;
 use crate::{GenKill, ResultsCursor};
 
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b0808ba2067..8708bebeeb0 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,4 +1,5 @@
 // tidy-alphabetical-start
+#![feature(assert_matches)]
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
 #![feature(exact_size_is_empty)]
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 7b39db821d8..c26a72e4543 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -1,3 +1,5 @@
+use std::mem;
+
 use rustc_index::IndexVec;
 use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState};
 use rustc_middle::mir::*;
@@ -6,12 +8,10 @@ use rustc_middle::{bug, span_bug};
 use smallvec::{smallvec, SmallVec};
 use tracing::debug;
 
-use std::mem;
-
 use super::abs_domain::Lift;
-use super::{Init, InitIndex, InitKind, InitLocation, LookupResult};
 use super::{
-    LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
+    Init, InitIndex, InitKind, InitLocation, LocationMap, LookupResult, MoveData, MoveOut,
+    MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
 };
 
 struct MoveDataBuilder<'a, 'tcx, F> {
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index 830f44df5fb..bc1177976b5 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -1,4 +1,6 @@
-use crate::un_derefer::UnDerefer;
+use std::fmt;
+use std::ops::{Index, IndexMut};
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::*;
@@ -6,10 +8,8 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::Span;
 use smallvec::SmallVec;
 
-use std::fmt;
-use std::ops::{Index, IndexMut};
-
 use self::abs_domain::{AbstractElem, Lift};
+use crate::un_derefer::UnDerefer;
 
 mod abs_domain;
 
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index bbfb37d2a82..4be7492366a 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -1,10 +1,10 @@
-use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor};
 use rustc_index::bit_set::BitSet;
 use rustc_index::interval::SparseIntervalMatrix;
-use rustc_index::Idx;
-use rustc_index::IndexVec;
+use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
+use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor};
+
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
 pub struct DenseLocationMap {
     /// For each basic block, how many points are contained within?
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 1de9055273b..0171cc85918 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,3 +1,12 @@
+use rustc_ast::MetaItem;
+use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::{self, Body, Local, Location, MirPass};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
+use tracing::{debug, info};
+
 use crate::errors::{
     PeekArgumentNotALocal, PeekArgumentUntracked, PeekBitNotSet, PeekMustBeNotTemporary,
     PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation,
@@ -6,19 +15,8 @@ use crate::framework::BitSetExt;
 use crate::impls::{
     DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
 };
-use crate::move_paths::{HasMoveData, MoveData};
-use crate::move_paths::{LookupResult, MovePathIndex};
-use crate::MoveDataParamEnv;
+use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
 use crate::{Analysis, JoinSemiLattice, ResultsCursor};
-use rustc_ast::MetaItem;
-use rustc_hir::def_id::DefId;
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::MirPass;
-use rustc_middle::mir::{self, Body, Local, Location};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
-use tracing::{debug, info};
 
 pub struct SanityCheck;
 
@@ -48,10 +46,9 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
 
         let param_env = tcx.param_env(def_id);
         let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
-        let mdpe = MoveDataParamEnv { move_data, param_env };
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
-            let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+            let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
@@ -59,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
-            let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
+            let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
@@ -67,7 +64,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
-            let flow_def_inits = DefinitelyInitializedPlaces::new(body, &mdpe)
+            let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index c9f5d38fe2c..139fd592f69 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -32,6 +32,7 @@
 //! Because of that, we can assume that the only way to change the value behind a tracked place is
 //! by direct assignment.
 
+use std::assert_matches::assert_matches;
 use std::fmt::{Debug, Formatter};
 use std::ops::Range;
 
@@ -48,14 +49,13 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use tracing::debug;
 
+use crate::fmt::DebugWithContext;
 use crate::lattice::{HasBottom, HasTop};
-use crate::{
-    fmt::DebugWithContext, Analysis, AnalysisDomain, JoinSemiLattice, SwitchIntEdgeEffects,
-};
+use crate::{Analysis, AnalysisDomain, JoinSemiLattice, SwitchIntEdgeEffects};
 
 pub trait ValueAnalysis<'tcx> {
     /// For each place of interest, the analysis tracks a value of the given type.
-    type Value: Clone + JoinSemiLattice + HasBottom + HasTop;
+    type Value: Clone + JoinSemiLattice + HasBottom + HasTop + Debug;
 
     const NAME: &'static str;
 
@@ -345,7 +345,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
 
     fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
         // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
-        assert!(matches!(state, State::Unreachable));
+        assert_matches!(state, State::Unreachable);
         *state = State::new_reachable();
         for arg in body.args_iter() {
             state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index f864a13a31b..07ca51a67ae 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -25,6 +25,7 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index d43fca3dc7e..f52a4524d78 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,8 +1,7 @@
 use rustc_ast::InlineAsmOptions;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
-use rustc_middle::ty::layout;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, layout, TyCtxt};
 use rustc_target::spec::abi::Abi;
 use rustc_target::spec::PanicStrategy;
 
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index de6d20ae3e8..cd850e2d731 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -1,8 +1,8 @@
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
 use crate::util;
-use rustc_middle::mir::patch::MirPatch;
 
 /// This pass moves values being dropped that are within a packed
 /// struct to a separate local before dropping them, to ensure that
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 5199c41c58c..a1dbd7dc50e 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -1,10 +1,8 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_index::IndexVec;
+use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::mir::{
-    interpret::Scalar,
-    visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor},
-};
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::Session;
 
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 5f67bd75c48..9902002580a 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -3,8 +3,7 @@ use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt};
 
-use crate::MirLint;
-use crate::{errors, util};
+use crate::{errors, util, MirLint};
 
 pub struct CheckPackedRef;
 
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 264d8a13996..08c9f9f08e6 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -16,12 +16,13 @@
 //! [`BlockMarker`]: rustc_middle::mir::coverage::CoverageKind::BlockMarker
 //! [`SpanMarker`]: rustc_middle::mir::coverage::CoverageKind::SpanMarker
 
-use crate::MirPass;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::{Body, BorrowKind, CastKind, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::TyCtxt;
 
+use crate::MirPass;
+
 pub struct CleanupPostBorrowck;
 
 impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 658cc4c51a9..82528109be9 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -51,13 +51,9 @@
 //! Otherwise it drops all the values in scope at the last suspension point.
 
 mod by_move_body;
-pub use by_move_body::ByMoveBody;
+use std::{iter, ops};
 
-use crate::abort_unwinding_calls;
-use crate::deref_separator::deref_finder;
-use crate::errors;
-use crate::pass_manager as pm;
-use crate::simplify;
+pub use by_move_body::ByMoveBody;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::pluralize;
 use rustc_hir as hir;
@@ -67,9 +63,7 @@ use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet};
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::CoroutineArgs;
-use rustc_middle::ty::InstanceKind;
-use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TyCtxt};
+use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, InstanceKind, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
@@ -83,9 +77,10 @@ use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::TyCtxtInferExt as _;
-use rustc_trait_selection::traits::ObligationCtxt;
-use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
-use std::{iter, ops};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
+
+use crate::deref_separator::deref_finder;
+use crate::{abort_unwinding_calls, errors, pass_manager as pm, simplify};
 
 pub struct StateTransform;
 
@@ -1167,10 +1162,11 @@ fn insert_switch<'tcx>(
 }
 
 fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    use crate::shim::DropShimElaborator;
     use rustc_middle::mir::patch::MirPatch;
     use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, Unwind};
 
+    use crate::shim::DropShimElaborator;
+
     // Note that `elaborate_drops` only drops the upvars of a coroutine, and
     // this is ok because `open_drop` can only be reached within that own
     // coroutine's resume function.
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 83fb9ff9743..31b20775194 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,3 +1,7 @@
+use std::cmp::Ordering;
+use std::collections::VecDeque;
+use std::ops::{Index, IndexMut};
+
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{self, Dominators};
@@ -7,10 +11,6 @@ use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
 
-use std::cmp::Ordering;
-use std::collections::VecDeque;
-use std::ops::{Index, IndexMut};
-
 /// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s
 /// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s.
 #[derive(Debug)]
@@ -350,8 +350,8 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
         // An inline asm terminator can normally be chained, except when it diverges or uses asm
         // goto.
         InlineAsm { ref targets, .. } => {
-            if targets.len() == 1 {
-                CoverageSuccessors::Chainable(targets[0])
+            if let [target] = targets[..] {
+                CoverageSuccessors::Chainable(target)
             } else {
                 CoverageSuccessors::NotChainable(targets)
             }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 3772a8f5118..96ca3b43d5c 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -147,7 +147,8 @@ fn create_mappings<'tcx>(
 
     let source_file = source_map.lookup_source_file(body_span.lo());
 
-    use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+    use rustc_session::config::RemapPathScopeComponents;
+    use rustc_session::RemapFileNameExt;
     let file_name = Symbol::intern(
         &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
     );
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index dbc26a2808e..092ec1e06d2 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -6,11 +6,10 @@ use rustc_middle::mir;
 use rustc_span::Span;
 
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
-use crate::coverage::mappings;
 use crate::coverage::spans::from_mir::{
     extract_covspans_from_mir, ExtractedCovspans, Hole, SpanFromMir,
 };
-use crate::coverage::ExtractedHirInfo;
+use crate::coverage::{mappings, ExtractedHirInfo};
 
 mod from_mir;
 
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 63a9f303b85..a4db11bb2c1 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -24,16 +24,15 @@
 //! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument
 //! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`.
 
-use super::graph::{self, BasicCoverageBlock};
-
 use itertools::Itertools;
 use rustc_data_structures::graph::{DirectedGraph, Successors};
 use rustc_index::{Idx, IndexVec};
-use rustc_middle::bug;
 use rustc_middle::mir::*;
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 
+use super::graph::{self, BasicCoverageBlock};
+
 fn bcb(index: u32) -> BasicCoverageBlock {
     BasicCoverageBlock::from_u32(index)
 }
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 483fd753e70..50aaed090f6 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -1,5 +1,3 @@
-use crate::inline;
-use crate::pass_manager as pm;
 use rustc_attr::InlineAttr;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -7,10 +5,11 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::InliningThreshold;
-use rustc_session::config::OptLevel;
+use rustc_session::config::{InliningThreshold, OptLevel};
 use rustc_span::sym;
 
+use crate::{inline, pass_manager as pm};
+
 pub fn provide(providers: &mut Providers) {
     providers.cross_crate_inlinable = cross_crate_inlinable;
 }
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
index a0dddec185c..ff9fc776e54 100644
--- a/compiler/rustc_mir_transform/src/ctfe_limit.rs
+++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs
@@ -1,14 +1,14 @@
 //! A pass that inserts the `ConstEvalCounter` instruction into any blocks that have a back edge
 //! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
 
-use crate::MirPass;
-
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::{
     BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
 
+use crate::MirPass;
+
 pub struct CtfeLimit;
 
 impl<'tcx> MirPass<'tcx> for CtfeLimit {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 8303ef039d1..0fc4d6b9f4e 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -12,10 +12,11 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_mir_dataflow::lattice::FlatSet;
 use rustc_mir_dataflow::value_analysis::{
     Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
 };
-use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
+use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 60230bea02e..f473073083a 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -12,7 +12,6 @@
 //!     will still not cause any further changes.
 //!
 
-use crate::util::is_within_packed;
 use rustc_middle::bug;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
@@ -23,6 +22,8 @@ use rustc_mir_dataflow::impls::{
 };
 use rustc_mir_dataflow::Analysis;
 
+use crate::util::is_within_packed;
+
 /// Performs the optimization on the body
 ///
 /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index 824974970bb..4a94c3eca86 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -1,7 +1,9 @@
 //! This pass finds basic blocks that are completely equal,
 //! and replaces all uses with just one of them.
 
-use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter};
+use std::collections::hash_map::Entry;
+use std::hash::{Hash, Hasher};
+use std::iter;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::visit::MutVisitor;
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index ab73a8af317..054cdbc6bad 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -131,23 +131,22 @@
 //! [attempt 2]: https://github.com/rust-lang/rust/pull/71003
 //! [attempt 3]: https://github.com/rust-lang/rust/pull/72632
 
-use crate::MirPass;
 use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry};
 use rustc_index::bit_set::BitSet;
 use rustc_index::interval::SparseIntervalMatrix;
 use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
-use rustc_middle::mir::HasLocalDecls;
-use rustc_middle::mir::{dump_mir, PassWhere};
 use rustc_middle::mir::{
-    traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, Rvalue,
-    Statement, StatementKind, TerminatorKind,
+    dump_mir, traversal, Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location,
+    Operand, PassWhere, Place, Rvalue, Statement, StatementKind, TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::MaybeLiveLocals;
 use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex};
 use rustc_mir_dataflow::Analysis;
 
+use crate::MirPass;
+
 pub struct DestinationPropagation;
 
 impl<'tcx> MirPass<'tcx> for DestinationPropagation {
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 3b71cf02c1a..29db45f9450 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -3,12 +3,12 @@
 use std::fs::File;
 use std::io;
 
-use crate::MirPass;
-use rustc_middle::mir::write_mir_pretty;
-use rustc_middle::mir::Body;
+use rustc_middle::mir::{write_mir_pretty, Body};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OutFileName, OutputType};
 
+use crate::MirPass;
+
 pub struct Marker(pub &'static str);
 
 impl<'tcx> MirPass<'tcx> for Marker {
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 40c0c723d25..49e41c35f1f 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -1,7 +1,8 @@
+use std::fmt::Debug;
+
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
-use std::fmt::Debug;
 
 use super::simplify::simplify_cfg;
 
@@ -308,11 +309,11 @@ fn verify_candidate_branch<'tcx>(
 ) -> bool {
     // In order for the optimization to be correct, the branch must...
     // ...have exactly one statement
-    if branch.statements.len() != 1 {
+    let [statement] = branch.statements.as_slice() else {
         return false;
-    }
+    };
     // ...assign the discriminant of `place` in that statement
-    let StatementKind::Assign(boxed) = &branch.statements[0].kind else { return false };
+    let StatementKind::Assign(boxed) = &statement.kind else { return false };
     let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { return false };
     if *from_place != place {
         return false;
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index d955b96d06a..e5778f8a05d 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -116,29 +116,30 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
             for debug_info in body.var_debug_info.iter_mut() {
                 if let VarDebugInfoContents::Place(place) = &mut debug_info.value {
                     let mut new_projections: Option<Vec<_>> = None;
-                    let mut last_deref = 0;
 
-                    for (i, (base, elem)) in place.iter_projections().enumerate() {
+                    for (base, elem) in place.iter_projections() {
                         let base_ty = base.ty(&body.local_decls, tcx).ty;
 
                         if elem == PlaceElem::Deref && base_ty.is_box() {
-                            let new_projections = new_projections.get_or_insert_default();
+                            // Clone the projections before us, since now we need to mutate them.
+                            let new_projections =
+                                new_projections.get_or_insert_with(|| base.projection.to_vec());
 
                             let (unique_ty, nonnull_ty, ptr_ty) =
                                 build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did);
 
-                            new_projections.extend_from_slice(&base.projection[last_deref..]);
                             new_projections.extend_from_slice(&build_projection(
                                 unique_ty, nonnull_ty, ptr_ty,
                             ));
                             new_projections.push(PlaceElem::Deref);
-
-                            last_deref = i;
+                        } else if let Some(new_projections) = new_projections.as_mut() {
+                            // Keep building up our projections list once we've started it.
+                            new_projections.push(elem);
                         }
                     }
 
-                    if let Some(mut new_projections) = new_projections {
-                        new_projections.extend_from_slice(&place.projection[last_deref..]);
+                    // Store the mutated projections if we actually changed something.
+                    if let Some(new_projections) = new_projections {
                         place.projection = tcx.mk_place_elems(&new_projections);
                     }
                 }
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 25bebb0539a..5a22ef77903 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -1,20 +1,22 @@
-use crate::deref_separator::deref_finder;
+use std::fmt;
+
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, DropFlagState, Unwind};
-use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle};
+use rustc_mir_dataflow::elaborate_drops::{
+    elaborate_drop, DropElaborator, DropFlagMode, DropFlagState, DropStyle, Unwind,
+};
 use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
-use rustc_mir_dataflow::on_all_children_bits;
-use rustc_mir_dataflow::on_lookup_result_bits;
-use rustc_mir_dataflow::MoveDataParamEnv;
-use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use rustc_mir_dataflow::{
+    on_all_children_bits, on_lookup_result_bits, Analysis, MoveDataParamEnv, ResultsCursor,
+};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
-use std::fmt;
+
+use crate::deref_separator::deref_finder;
 
 /// During MIR building, Drop terminators are inserted in every place where a drop may occur.
 /// However, in this phase, the presence of these terminators does not guarantee that a destructor will run,
@@ -60,7 +62,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
         let elaborate_patch = {
             let env = MoveDataParamEnv { move_data, param_env };
 
-            let mut inits = MaybeInitializedPlaces::new(tcx, body, &env)
+            let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
                 .skipping_unreachable_unwind()
                 .into_engine(tcx, body)
                 .pass_name("elaborate_drops")
@@ -68,7 +70,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
                 .into_results_cursor(body);
             let dead_unwinds = compute_dead_unwinds(body, &mut inits);
 
-            let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
+            let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data)
                 .mark_inactive_variants_as_uninit()
                 .skipping_unreachable_unwind(dead_unwinds)
                 .into_engine(tcx, body)
@@ -441,9 +443,13 @@ impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> {
 
     fn drop_flags_for_args(&mut self) {
         let loc = Location::START;
-        rustc_mir_dataflow::drop_flag_effects_for_function_entry(self.body, self.env, |path, ds| {
-            self.set_drop_flag(loc, path, ds);
-        })
+        rustc_mir_dataflow::drop_flag_effects_for_function_entry(
+            self.body,
+            &self.env.move_data,
+            |path, ds| {
+                self.set_drop_flag(loc, path, ds);
+            },
+        )
     }
 
     fn drop_flags_for_locs(&mut self) {
@@ -476,7 +482,7 @@ impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> {
                 let loc = Location { block: bb, statement_index: i };
                 rustc_mir_dataflow::drop_flag_effects_for_location(
                     self.body,
-                    self.env,
+                    &self.env.move_data,
                     loc,
                     |path, ds| self.set_drop_flag(loc, path, ds),
                 )
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index dc7648d27b5..2703dc57cda 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -1,4 +1,5 @@
-use rustc_errors::{codes::*, Diag, LintDiagnostic};
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, LintDiagnostic};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index 0cb304da80a..4132e604f20 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,9 +1,7 @@
 use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_middle::mir::*;
-use rustc_middle::query::LocalCrate;
-use rustc_middle::query::Providers;
-use rustc_middle::ty::layout;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::query::{LocalCrate, Providers};
+use rustc_middle::ty::{self, layout, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
 use rustc_target::spec::abi::Abi;
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 434529ccff4..b7873e73c18 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -5,7 +5,8 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt};
 use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::source_map::Spanned;
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 use crate::{errors, MirLint};
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 1002746e553..e16911d79c3 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -82,15 +82,19 @@
 //! Second, when writing constants in MIR, we do not write `Const::Slice` or `Const`
 //! that contain `AllocId`s.
 
+use std::borrow::Cow;
+
+use either::Either;
 use rustc_const_eval::const_eval::DummyMachine;
-use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemPlaceMeta, MemoryKind};
-use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable, Scalar};
+use rustc_const_eval::interpret::{
+    intern_const_alloc_for_constprop, ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy,
+    Projectable, Scalar,
+};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
-use rustc_index::newtype_index;
-use rustc_index::IndexVec;
+use rustc_index::{newtype_index, IndexVec};
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::GlobalAlloc;
 use rustc_middle::mir::visit::*;
@@ -101,10 +105,8 @@ use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 use smallvec::SmallVec;
-use std::borrow::Cow;
 
 use crate::ssa::{AssignedValue, SsaLocals};
-use either::Either;
 
 pub struct GVN;
 
@@ -126,7 +128,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     // Clone dominators as we need them while mutating the body.
     let dominators = body.basic_blocks.dominators().clone();
 
-    let mut state = VnState::new(tcx, param_env, &ssa, &dominators, &body.local_decls);
+    let mut state = VnState::new(tcx, body, param_env, &ssa, &dominators, &body.local_decls);
     ssa.for_each_assignment_mut(
         body.basic_blocks.as_mut_preserves_cfg(),
         |local, value, location| {
@@ -202,6 +204,7 @@ enum Value<'tcx> {
         value: Const<'tcx>,
         /// Some constants do not have a deterministic value. To avoid merging two instances of the
         /// same `Const`, we assign them an additional integer index.
+        // `disambiguator` is 0 iff the constant is deterministic.
         disambiguator: usize,
     },
     /// An aggregate value, either tuple/closure/struct/enum.
@@ -264,21 +267,29 @@ struct VnState<'body, 'tcx> {
 impl<'body, 'tcx> VnState<'body, 'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
+        body: &Body<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         ssa: &'body SsaLocals,
         dominators: &'body Dominators<BasicBlock>,
         local_decls: &'body LocalDecls<'tcx>,
     ) -> Self {
+        // Compute a rough estimate of the number of values in the body from the number of
+        // statements. This is meant to reduce the number of allocations, but it's all right if
+        // we miss the exact amount. We estimate based on 2 values per statement (one in LHS and
+        // one in RHS) and 4 values per terminator (for call operands).
+        let num_values =
+            2 * body.basic_blocks.iter().map(|bbdata| bbdata.statements.len()).sum::<usize>()
+                + 4 * body.basic_blocks.len();
         VnState {
             tcx,
             ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
             param_env,
             local_decls,
             locals: IndexVec::from_elem(None, local_decls),
-            rev_locals: IndexVec::default(),
-            values: FxIndexSet::default(),
-            evaluated: IndexVec::new(),
-            next_opaque: Some(0),
+            rev_locals: IndexVec::with_capacity(num_values),
+            values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
+            evaluated: IndexVec::with_capacity(num_values),
+            next_opaque: Some(1),
             feature_unsized_locals: tcx.features().unsized_locals,
             ssa,
             dominators,
@@ -291,9 +302,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         let (index, new) = self.values.insert_full(value);
         let index = VnIndex::from_usize(index);
         if new {
+            // Grow `evaluated` and `rev_locals` here to amortize the allocations.
             let evaluated = self.eval_to_const(index);
             let _index = self.evaluated.push(evaluated);
             debug_assert_eq!(index, _index);
+            // No need to push to `rev_locals` if we finished listing assignments.
+            if self.next_opaque.is_some() {
+                let _index = self.rev_locals.push(SmallVec::new());
+                debug_assert_eq!(index, _index);
+            }
         }
         index
     }
@@ -330,7 +347,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         let is_sized = !self.feature_unsized_locals
             || self.local_decls[local].ty.is_sized(self.tcx, self.param_env);
         if is_sized {
-            self.rev_locals.ensure_contains_elem(value, SmallVec::new).push(local);
+            self.rev_locals[value].push(local);
         }
     }
 
@@ -344,6 +361,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             let next_opaque = self.next_opaque.as_mut()?;
             let disambiguator = *next_opaque;
             *next_opaque += 1;
+            // `disambiguator: 0` means deterministic.
+            debug_assert_ne!(disambiguator, 0);
             disambiguator
         };
         Some(self.insert(Value::Constant { value, disambiguator }))
@@ -351,12 +370,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
     fn insert_bool(&mut self, flag: bool) -> VnIndex {
         // Booleans are deterministic.
-        self.insert(Value::Constant { value: Const::from_bool(self.tcx, flag), disambiguator: 0 })
+        let value = Const::from_bool(self.tcx, flag);
+        debug_assert!(value.is_deterministic());
+        self.insert(Value::Constant { value, disambiguator: 0 })
     }
 
     fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
-        self.insert_constant(Const::from_scalar(self.tcx, scalar, ty))
-            .expect("scalars are deterministic")
+        // Scalars are deterministic.
+        let value = Const::from_scalar(self.tcx, scalar, ty);
+        debug_assert!(value.is_deterministic());
+        self.insert(Value::Constant { value, disambiguator: 0 })
     }
 
     fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
@@ -669,7 +692,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     fn simplify_place_projection(&mut self, place: &mut Place<'tcx>, location: Location) {
         // If the projection is indirect, we treat the local as a value, so can replace it with
         // another local.
-        if place.is_indirect()
+        if place.is_indirect_first_projection()
             && let Some(base) = self.locals[place.local]
             && let Some(new_local) = self.try_as_local(base, location)
             && place.local != new_local
@@ -771,10 +794,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         location: Location,
     ) -> Option<VnIndex> {
         match *operand {
-            Operand::Constant(ref mut constant) => {
-                let const_ = constant.const_.normalize(self.tcx, self.param_env);
-                self.insert_constant(const_)
-            }
+            Operand::Constant(ref constant) => self.insert_constant(constant.const_),
             Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
                 let value = self.simplify_place_value(place, location)?;
                 if let Some(const_) = self.try_as_constant(value) {
@@ -1369,8 +1389,13 @@ fn op_to_prop_const<'tcx>(
     // If this constant has scalar ABI, return it as a `ConstValue::Scalar`.
     if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi
         && let Ok(scalar) = ecx.read_scalar(op)
-        && scalar.try_to_scalar_int().is_ok()
     {
+        if !scalar.try_to_scalar_int().is_ok() {
+            // Check that we do not leak a pointer.
+            // Those pointers may lose part of their identity in codegen.
+            // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
+            return None;
+        }
         return Some(ConstValue::Scalar(scalar));
     }
 
@@ -1434,12 +1459,11 @@ impl<'tcx> VnState<'_, 'tcx> {
 
     /// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
     fn try_as_constant(&mut self, index: VnIndex) -> Option<ConstOperand<'tcx>> {
-        // This was already constant in MIR, do not change it.
-        if let Value::Constant { value, disambiguator: _ } = *self.get(index)
-            // If the constant is not deterministic, adding an additional mention of it in MIR will
-            // not give the same value as the former mention.
-            && value.is_deterministic()
-        {
+        // This was already constant in MIR, do not change it. If the constant is not
+        // deterministic, adding an additional mention of it in MIR will not give the same value as
+        // the former mention.
+        if let Value::Constant { value, disambiguator: 0 } = *self.get(index) {
+            debug_assert!(value.is_deterministic());
             return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value });
         }
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index fd9f0fec88d..324ddc5e799 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,6 +1,8 @@
 //! Inlining pass for MIR functions.
 
-use crate::deref_separator::deref_finder;
+use std::iter;
+use std::ops::{Range, RangeFrom};
+
 use rustc_attr::InlineAttr;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -10,8 +12,9 @@ use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags};
+use rustc_middle::ty::{
+    self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags, TypeVisitableExt,
+};
 use rustc_session::config::{DebugInfo, OptLevel};
 use rustc_span::source_map::Spanned;
 use rustc_span::sym;
@@ -19,11 +22,10 @@ use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi::Abi;
 
 use crate::cost_checker::CostChecker;
+use crate::deref_separator::deref_finder;
 use crate::simplify::simplify_cfg;
 use crate::util;
 use crate::validate::validate_types;
-use std::iter;
-use std::ops::{Range, RangeFrom};
 
 pub(crate) mod cycle;
 
@@ -477,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
             return Err("incompatible instruction set");
         }
 
-        if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
+        let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
+        let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
+        if callee_feature_names.ne(this_feature_names) {
             // In general it is not correct to inline a callee with target features that are a
             // subset of the caller. This is because the callee might contain calls, and the ABI of
             // those calls depends on the target features of the surrounding function. By moving a
@@ -501,6 +505,10 @@ impl<'tcx> Inliner<'tcx> {
     ) -> Result<(), &'static str> {
         let tcx = self.tcx;
 
+        if let Some(_) = callee_body.tainted_by_errors {
+            return Err("Body is tainted");
+        }
+
         let mut threshold = if self.caller_is_inline_forwarder {
             self.tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30)
         } else if cross_crate_inlinable {
@@ -742,8 +750,8 @@ impl<'tcx> Inliner<'tcx> {
         // Copy required constants from the callee_body into the caller_body. Although we are only
         // pushing unevaluated consts to `required_consts`, here they may have been evaluated
         // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again.
-        caller_body.required_consts.extend(
-            callee_body.required_consts.into_iter().filter(|ct| ct.const_.is_required_const()),
+        caller_body.required_consts.as_mut().unwrap().extend(
+            callee_body.required_consts().into_iter().filter(|ct| ct.const_.is_required_const()),
         );
         // Now that we incorporated the callee's `required_consts`, we can remove the callee from
         // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does
@@ -753,12 +761,11 @@ impl<'tcx> Inliner<'tcx> {
         // We need to reconstruct the `required_item` for the callee so that we can find and
         // remove it.
         let callee_item = MentionedItem::Fn(func.ty(caller_body, self.tcx));
-        if let Some(idx) =
-            caller_body.mentioned_items.iter().position(|item| item.node == callee_item)
-        {
+        let caller_mentioned_items = caller_body.mentioned_items.as_mut().unwrap();
+        if let Some(idx) = caller_mentioned_items.iter().position(|item| item.node == callee_item) {
             // We found the callee, so remove it and add its items instead.
-            caller_body.mentioned_items.remove(idx);
-            caller_body.mentioned_items.extend(callee_body.mentioned_items);
+            caller_mentioned_items.remove(idx);
+            caller_mentioned_items.extend(callee_body.mentioned_items());
         } else {
             // If we can't find the callee, there's no point in adding its items. Probably it
             // already got removed by being inlined elsewhere in the same function, so we already
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index d4477563e3a..f5274c664cf 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -2,8 +2,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir::TerminatorKind;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt};
 use rustc_session::Limit;
 use rustc_span::sym;
 
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 58fdc2d9e45..1589653968c 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -1,21 +1,37 @@
 //! Performs various peephole optimizations.
 
-use crate::simplify::simplify_duplicate_switch_targets;
-use crate::take_array;
 use rustc_ast::attr;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::mir::*;
-use rustc_middle::ty::layout;
 use rustc_middle::ty::layout::ValidityRequirement;
-use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, layout, GenericArgsRef, ParamEnv, Ty, TyCtxt};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::abi::Abi;
 
-pub struct InstSimplify;
+use crate::simplify::simplify_duplicate_switch_targets;
+use crate::take_array;
+
+pub enum InstSimplify {
+    BeforeInline,
+    AfterSimplifyCfg,
+}
+
+impl InstSimplify {
+    pub fn name(&self) -> &'static str {
+        match self {
+            InstSimplify::BeforeInline => "InstSimplify-before-inline",
+            InstSimplify::AfterSimplifyCfg => "InstSimplify-after-simplifycfg",
+        }
+    }
+}
 
 impl<'tcx> MirPass<'tcx> for InstSimplify {
+    fn name(&self) -> &'static str {
+        self.name()
+    }
+
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
@@ -248,9 +264,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
         };
 
         // It's definitely not a clone if there are multiple arguments
-        if args.len() != 1 {
-            return;
-        }
+        let [arg] = &args[..] else { return };
 
         let Some(destination_block) = *target else { return };
 
@@ -264,7 +278,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
 
         // These types are easily available from locals, so check that before
         // doing DefId lookups to figure out what we're actually calling.
-        let arg_ty = args[0].node.ty(self.local_decls, self.tcx);
+        let arg_ty = arg.node.ty(self.local_decls, self.tcx);
 
         let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
 
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 82ad8879d17..7202cc2d042 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -13,7 +13,8 @@ use rustc_const_eval::interpret::{
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
-use rustc_index::{bit_set::BitSet, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 243c9c6a2fd..1f214bc42cb 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -28,17 +28,16 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::IndexVec;
-use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{
-    traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs,
-    LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue,
-    SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
+    AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
+    MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
+    Statement, StatementKind, TerminatorKind, START_BLOCK,
 };
-use rustc_middle::query;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::util::Providers;
-use rustc_middle::{bug, span_bug};
-use rustc_span::{source_map::Spanned, sym, DUMMY_SP};
+use rustc_middle::{bug, query, span_bug};
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, DUMMY_SP};
 use rustc_trait_selection::traits;
 
 #[macro_use]
@@ -339,12 +338,15 @@ fn mir_promoted(
 
     // Collect `required_consts` *before* promotion, so if there are any consts being promoted
     // we still add them to the list in the outer MIR body.
-    let mut required_consts = Vec::new();
-    let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
-    for (bb, bb_data) in traversal::reverse_postorder(&body) {
-        required_consts_visitor.visit_basic_block_data(bb, bb_data);
+    RequiredConstsVisitor::compute_required_consts(&mut body);
+    // If this has an associated by-move async closure body, that doesn't get run through these
+    // passes itself, it gets "tagged along" by the pass manager. `RequiredConstsVisitor` is not
+    // a regular pass so we have to also apply it manually to the other body.
+    if let Some(coroutine) = body.coroutine.as_mut() {
+        if let Some(by_move_body) = coroutine.by_move_body.as_mut() {
+            RequiredConstsVisitor::compute_required_consts(by_move_body);
+        }
     }
-    body.required_consts = required_consts;
 
     // What we need to run borrowck etc.
     let promote_pass = promote_consts::PromoteTemps::default();
@@ -561,9 +563,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         tcx,
         body,
         &[
-            // Before doing anything, remember which items are being mentioned so that the set of items
-            // visited does not depend on the optimization level.
-            &mentioned_items::MentionedItems,
             // Add some UB checks before any UB gets optimized away.
             &check_alignment::CheckAlignment,
             // Before inlining: trim down MIR with passes to reduce inlining work.
@@ -571,6 +570,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             // Has to be done before inlining, otherwise actual call will be almost always inlined.
             // Also simple, so can just do first
             &lower_slice_len::LowerSliceLenCalls,
+            // Perform instsimplify before inline to eliminate some trivial calls (like clone shims).
+            &instsimplify::InstSimplify::BeforeInline,
             // Perform inlining, which may add a lot of code.
             &inline::Inline,
             // Code from other crates may have storage markers, so this needs to happen after inlining.
@@ -590,7 +591,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &match_branches::MatchBranchSimplification,
             // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
             &multiple_return_terminators::MultipleReturnTerminators,
-            &instsimplify::InstSimplify,
+            // After simplifycfg, it allows us to discover new opportunities for peephole optimizations.
+            &instsimplify::InstSimplify::AfterSimplifyCfg,
             &simplify::SimplifyLocals::BeforeConstProp,
             &dead_store_elimination::DeadStoreElimination::Initial,
             &gvn::GVN,
@@ -654,6 +656,19 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
         return body;
     }
 
+    // Before doing anything, remember which items are being mentioned so that the set of items
+    // visited does not depend on the optimization level.
+    // We do not use `run_passes` for this as that might skip the pass if `injection_phase` is set.
+    mentioned_items::MentionedItems.run_pass(tcx, &mut body);
+    // If this has an associated by-move async closure body, that doesn't get run through these
+    // passes itself, it gets "tagged along" by the pass manager. Since we're not using the pass
+    // manager we have to do this by hand.
+    if let Some(coroutine) = body.coroutine.as_mut() {
+        if let Some(by_move_body) = coroutine.by_move_body.as_mut() {
+            mentioned_items::MentionedItems.run_pass(tcx, by_move_body);
+        }
+    }
+
     // If `mir_drops_elaborated_and_const_checked` found that the current body has unsatisfiable
     // predicates, it will shrink the MIR to a single `unreachable` terminator.
     // More generally, if MIR is a lone `unreachable`, there is nothing to optimize.
diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs
index 3d1e1e48175..746068064b8 100644
--- a/compiler/rustc_mir_transform/src/lint.rs
+++ b/compiler/rustc_mir_transform/src/lint.rs
@@ -2,6 +2,8 @@
 //! It can be used to locate problems in MIR building or optimizations. It assumes that all code
 //! can be executed, so it has false positives.
 
+use std::borrow::Cow;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -10,7 +12,6 @@ use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive};
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
-use std::borrow::Cow;
 
 pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) {
     let always_live_locals = &always_storage_live_locals(body);
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 6aa90394355..a9bdff95fe5 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -1,11 +1,12 @@
 //! Lowers intrinsic calls
 
-use crate::take_array;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 
+use crate::take_array;
+
 pub struct LowerIntrinsics;
 
 impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 6ab4ec6fe7e..47758b56f8c 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -1,9 +1,12 @@
+use std::iter;
+
 use rustc_index::IndexSlice;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
+use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
-use rustc_target::abi::Size;
-use std::iter;
+use rustc_target::abi::Integer;
+use rustc_type_ir::TyKind::*;
 
 use super::simplify::simplify_cfg;
 
@@ -41,10 +44,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                 should_cleanup = true;
                 continue;
             }
-            // unsound: https://github.com/rust-lang/rust/issues/124150
-            if tcx.sess.opts.unstable_opts.unsound_mir_opts
-                && SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some()
-            {
+            if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() {
                 should_cleanup = true;
                 continue;
             }
@@ -263,33 +263,56 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
     }
 }
 
+/// Check if the cast constant using `IntToInt` is equal to the target constant.
+fn can_cast(
+    tcx: TyCtxt<'_>,
+    src_val: impl Into<u128>,
+    src_layout: TyAndLayout<'_>,
+    cast_ty: Ty<'_>,
+    target_scalar: ScalarInt,
+) -> bool {
+    let from_scalar = ScalarInt::try_from_uint(src_val.into(), src_layout.size).unwrap();
+    let v = match src_layout.ty.kind() {
+        Uint(_) => from_scalar.to_uint(src_layout.size),
+        Int(_) => from_scalar.to_int(src_layout.size) as u128,
+        _ => unreachable!("invalid int"),
+    };
+    let size = match *cast_ty.kind() {
+        Int(t) => Integer::from_int_ty(&tcx, t).size(),
+        Uint(t) => Integer::from_uint_ty(&tcx, t).size(),
+        _ => unreachable!("invalid int"),
+    };
+    let v = size.truncate(v);
+    let cast_scalar = ScalarInt::try_from_uint(v, size).unwrap();
+    cast_scalar == target_scalar
+}
+
 #[derive(Default)]
 struct SimplifyToExp {
-    transfrom_types: Vec<TransfromType>,
+    transfrom_kinds: Vec<TransfromKind>,
 }
 
 #[derive(Clone, Copy)]
-enum CompareType<'tcx, 'a> {
+enum ExpectedTransformKind<'tcx, 'a> {
     /// Identical statements.
     Same(&'a StatementKind<'tcx>),
     /// Assignment statements have the same value.
-    Eq(&'a Place<'tcx>, Ty<'tcx>, ScalarInt),
+    SameByEq { place: &'a Place<'tcx>, ty: Ty<'tcx>, scalar: ScalarInt },
     /// Enum variant comparison type.
-    Discr { place: &'a Place<'tcx>, ty: Ty<'tcx>, is_signed: bool },
+    Cast { place: &'a Place<'tcx>, ty: Ty<'tcx> },
 }
 
-enum TransfromType {
+enum TransfromKind {
     Same,
-    Eq,
-    Discr,
+    Cast,
 }
 
-impl From<CompareType<'_, '_>> for TransfromType {
-    fn from(compare_type: CompareType<'_, '_>) -> Self {
+impl From<ExpectedTransformKind<'_, '_>> for TransfromKind {
+    fn from(compare_type: ExpectedTransformKind<'_, '_>) -> Self {
         match compare_type {
-            CompareType::Same(_) => TransfromType::Same,
-            CompareType::Eq(_, _, _) => TransfromType::Eq,
-            CompareType::Discr { .. } => TransfromType::Discr,
+            ExpectedTransformKind::Same(_) => TransfromKind::Same,
+            ExpectedTransformKind::SameByEq { .. } => TransfromKind::Same,
+            ExpectedTransformKind::Cast { .. } => TransfromKind::Cast,
         }
     }
 }
@@ -353,7 +376,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
             return None;
         }
         let mut target_iter = targets.iter();
-        let (first_val, first_target) = target_iter.next().unwrap();
+        let (first_case_val, first_target) = target_iter.next().unwrap();
         let first_terminator_kind = &bbs[first_target].terminator().kind;
         // Check that destinations are identical, and if not, then don't optimize this block
         if !targets
@@ -363,24 +386,20 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
             return None;
         }
 
-        let discr_size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
+        let discr_layout = tcx.layout_of(param_env.and(discr_ty)).unwrap();
         let first_stmts = &bbs[first_target].statements;
-        let (second_val, second_target) = target_iter.next().unwrap();
+        let (second_case_val, second_target) = target_iter.next().unwrap();
         let second_stmts = &bbs[second_target].statements;
         if first_stmts.len() != second_stmts.len() {
             return None;
         }
 
-        fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool {
-            l.to_bits_unchecked() == ScalarInt::try_from_uint(r, size).unwrap().to_bits_unchecked()
-        }
-
         // We first compare the two branches, and then the other branches need to fulfill the same conditions.
-        let mut compare_types = Vec::new();
+        let mut expected_transform_kinds = Vec::new();
         for (f, s) in iter::zip(first_stmts, second_stmts) {
             let compare_type = match (&f.kind, &s.kind) {
                 // If two statements are exactly the same, we can optimize.
-                (f_s, s_s) if f_s == s_s => CompareType::Same(f_s),
+                (f_s, s_s) if f_s == s_s => ExpectedTransformKind::Same(f_s),
 
                 // If two statements are assignments with the match values to the same place, we can optimize.
                 (
@@ -394,22 +413,29 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
                         f_c.const_.try_eval_scalar_int(tcx, param_env),
                         s_c.const_.try_eval_scalar_int(tcx, param_env),
                     ) {
-                        (Some(f), Some(s)) if f == s => CompareType::Eq(lhs_f, f_c.const_.ty(), f),
-                        // Enum variants can also be simplified to an assignment statement if their values are equal.
-                        // We need to consider both unsigned and signed scenarios here.
+                        (Some(f), Some(s)) if f == s => ExpectedTransformKind::SameByEq {
+                            place: lhs_f,
+                            ty: f_c.const_.ty(),
+                            scalar: f,
+                        },
+                        // Enum variants can also be simplified to an assignment statement,
+                        // if we can use `IntToInt` cast to get an equal value.
                         (Some(f), Some(s))
-                            if ((f_c.const_.ty().is_signed() || discr_ty.is_signed())
-                                && int_equal(f, first_val, discr_size)
-                                && int_equal(s, second_val, discr_size))
-                                || (Some(f) == ScalarInt::try_from_uint(first_val, f.size())
-                                    && Some(s)
-                                        == ScalarInt::try_from_uint(second_val, s.size())) =>
+                            if (can_cast(
+                                tcx,
+                                first_case_val,
+                                discr_layout,
+                                f_c.const_.ty(),
+                                f,
+                            ) && can_cast(
+                                tcx,
+                                second_case_val,
+                                discr_layout,
+                                f_c.const_.ty(),
+                                s,
+                            )) =>
                         {
-                            CompareType::Discr {
-                                place: lhs_f,
-                                ty: f_c.const_.ty(),
-                                is_signed: f_c.const_.ty().is_signed() || discr_ty.is_signed(),
-                            }
+                            ExpectedTransformKind::Cast { place: lhs_f, ty: f_c.const_.ty() }
                         }
                         _ => {
                             return None;
@@ -420,47 +446,36 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
                 // Otherwise we cannot optimize. Try another block.
                 _ => return None,
             };
-            compare_types.push(compare_type);
+            expected_transform_kinds.push(compare_type);
         }
 
         // All remaining BBs need to fulfill the same pattern as the two BBs from the previous step.
         for (other_val, other_target) in target_iter {
             let other_stmts = &bbs[other_target].statements;
-            if compare_types.len() != other_stmts.len() {
+            if expected_transform_kinds.len() != other_stmts.len() {
                 return None;
             }
-            for (f, s) in iter::zip(&compare_types, other_stmts) {
+            for (f, s) in iter::zip(&expected_transform_kinds, other_stmts) {
                 match (*f, &s.kind) {
-                    (CompareType::Same(f_s), s_s) if f_s == s_s => {}
+                    (ExpectedTransformKind::Same(f_s), s_s) if f_s == s_s => {}
                     (
-                        CompareType::Eq(lhs_f, f_ty, val),
+                        ExpectedTransformKind::SameByEq { place: lhs_f, ty: f_ty, scalar },
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
                     ) if lhs_f == lhs_s
                         && s_c.const_.ty() == f_ty
-                        && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(val) => {}
+                        && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(scalar) => {}
                     (
-                        CompareType::Discr { place: lhs_f, ty: f_ty, is_signed },
+                        ExpectedTransformKind::Cast { place: lhs_f, ty: f_ty },
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty => {
-                        let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) else {
-                            return None;
-                        };
-                        if is_signed
-                            && s_c.const_.ty().is_signed()
-                            && int_equal(f, other_val, discr_size)
-                        {
-                            continue;
-                        }
-                        if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) {
-                            continue;
-                        }
-                        return None;
-                    }
+                    ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env)
+                        && lhs_f == lhs_s
+                        && s_c.const_.ty() == f_ty
+                        && can_cast(tcx, other_val, discr_layout, f_ty, f) => {}
                     _ => return None,
                 }
             }
         }
-        self.transfrom_types = compare_types.into_iter().map(|c| c.into()).collect();
+        self.transfrom_kinds = expected_transform_kinds.into_iter().map(|c| c.into()).collect();
         Some(())
     }
 
@@ -478,13 +493,13 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
         let (_, first) = targets.iter().next().unwrap();
         let first = &bbs[first];
 
-        for (t, s) in iter::zip(&self.transfrom_types, &first.statements) {
+        for (t, s) in iter::zip(&self.transfrom_kinds, &first.statements) {
             match (t, &s.kind) {
-                (TransfromType::Same, _) | (TransfromType::Eq, _) => {
+                (TransfromKind::Same, _) => {
                     patch.add_statement(parent_end, s.kind.clone());
                 }
                 (
-                    TransfromType::Discr,
+                    TransfromKind::Cast,
                     StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
                 ) => {
                     let operand = Operand::Copy(Place::from(discr_local));
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index d928d7cf764..32c8064ebca 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -1,6 +1,7 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
-use rustc_middle::ty::{self, adjustment::PointerCoercion, TyCtxt};
+use rustc_middle::ty::adjustment::PointerCoercion;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 
@@ -22,10 +23,9 @@ impl<'tcx> MirPass<'tcx> for MentionedItems {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
-        debug_assert!(body.mentioned_items.is_empty());
         let mut mentioned_items = Vec::new();
         MentionedItemsVisitor { tcx, body, mentioned_items: &mut mentioned_items }.visit_body(body);
-        body.mentioned_items = mentioned_items;
+        body.set_mentioned_items(mentioned_items);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index 64749a4b5b6..1e87a0e01d9 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -1,11 +1,12 @@
 //! This pass removes jumps to basic blocks containing only a return, and replaces them with a
 //! return instead.
 
-use crate::simplify;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
+use crate::simplify;
+
 pub struct MultipleReturnTerminators;
 
 impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 17a1c3c7157..824a4b2f2df 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -2,7 +2,8 @@ use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 
-use crate::{lint::lint_body, validate, MirPass};
+use crate::lint::lint_body;
+use crate::{validate, MirPass};
 
 /// Just like `MirPass`, except it cannot mutate `Body`.
 pub trait MirLint<'tcx> {
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
index 7b77d032353..14dd0c6f61e 100644
--- a/compiler/rustc_mir_transform/src/prettify.rs
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -4,7 +4,8 @@
 //! (`-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals`)
 //! to make the MIR easier to read for humans.
 
-use rustc_index::{bit_set::BitSet, IndexSlice, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 736647fb64b..48a3266ae6f 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -12,25 +12,21 @@
 //! initialization and can otherwise silence errors, if
 //! move analysis runs after promotion on broken MIR.
 
+use std::assert_matches::assert_matches;
+use std::cell::Cell;
+use std::{cmp, iter, mem};
+
 use either::{Left, Right};
+use rustc_const_eval::check_consts::{qualifs, ConstCx};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_middle::mir;
+use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, List, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::{bug, span_bug};
-use rustc_span::Span;
-
-use rustc_index::{Idx, IndexSlice, IndexVec};
+use rustc_middle::ty::{self, GenericArgs, List, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_span::source_map::Spanned;
-
-use std::assert_matches::assert_matches;
-use std::cell::Cell;
-use std::{cmp, iter, mem};
-
-use rustc_const_eval::check_consts::{qualifs, ConstCx};
+use rustc_span::Span;
 
 /// A `MirPass` for promotion.
 ///
@@ -472,7 +468,7 @@ impl<'tcx> Validator<'_, 'tcx> {
 
                 if let ty::RawPtr(_, _) | ty::FnPtr(..) = lhs_ty.kind() {
                     // Raw and fn pointer operations are not allowed inside consts and thus not promotable.
-                    assert!(matches!(
+                    assert_matches!(
                         op,
                         BinOp::Eq
                             | BinOp::Ne
@@ -481,7 +477,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                             | BinOp::Ge
                             | BinOp::Gt
                             | BinOp::Offset
-                    ));
+                    );
                     return Err(Unpromotable);
                 }
 
@@ -706,6 +702,9 @@ struct Promoter<'a, 'tcx> {
     temps: &'a mut IndexVec<Local, TempState>,
     extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
 
+    /// Used to assemble the required_consts list while building the promoted.
+    required_consts: Vec<ConstOperand<'tcx>>,
+
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
     keep_original: bool,
@@ -928,11 +927,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         let span = self.promoted.span;
         self.assign(RETURN_PLACE, rvalue, span);
 
-        // Now that we did promotion, we know whether we'll want to add this to `required_consts`.
+        // Now that we did promotion, we know whether we'll want to add this to `required_consts` of
+        // the surrounding MIR body.
         if self.add_to_required {
-            self.source.required_consts.push(promoted_op);
+            self.source.required_consts.as_mut().unwrap().push(promoted_op);
         }
 
+        self.promoted.set_required_consts(self.required_consts);
+
         self.promoted
     }
 }
@@ -951,7 +953,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
 
     fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) {
         if constant.const_.is_required_const() {
-            self.promoted.required_consts.push(*constant);
+            self.required_consts.push(*constant);
         }
 
         // Skipping `super_constant` as the visitor is otherwise only looking for locals.
@@ -1015,9 +1017,9 @@ fn promote_candidates<'tcx>(
             extra_statements: &mut extra_statements,
             keep_original: false,
             add_to_required: false,
+            required_consts: Vec::new(),
         };
 
-        // `required_consts` of the promoted itself gets filled while building the MIR body.
         let mut promoted = promoter.promote_candidate(candidate, promotions.len());
         promoted.source.promoted = Some(promotions.next_index());
         promotions.push(promoted);
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 801ef14c9cd..76e65099e90 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
@@ -8,7 +10,6 @@ use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::MaybeStorageDead;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::Analysis;
-use std::borrow::Cow;
 
 use crate::ssa::{SsaLocals, StorageLiveLocals};
 
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 7d12bcf2fa1..fae1cb5f7d8 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -1,10 +1,9 @@
 use rustc_index::bit_set::ChunkedBitSet;
 use rustc_middle::mir::{Body, TerminatorKind};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
+use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, VariantDef};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
-use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable, MoveDataParamEnv};
+use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable};
 use rustc_target::abi::FieldIdx;
 
 use crate::MirPass;
@@ -25,8 +24,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
         let move_data =
             MoveData::gather_moves(body, tcx, param_env, |ty| ty.needs_drop(tcx, param_env));
 
-        let mdpe = MoveDataParamEnv { move_data, param_env };
-        let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+        let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
             .into_engine(tcx, body)
             .pass_name("remove_uninit_drops")
             .iterate_to_fixpoint()
@@ -41,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
             let MaybeReachable::Reachable(maybe_inits) = maybe_inits.get() else { continue };
 
             // If there's no move path for the dropped place, it's probably a `Deref`. Let it alone.
-            let LookupResult::Exact(mpi) = mdpe.move_data.rev_lookup.find(place.as_ref()) else {
+            let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) else {
                 continue;
             };
 
@@ -49,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
                 tcx,
                 param_env,
                 maybe_inits,
-                &mdpe.move_data,
+                &move_data,
                 place.ty(body, tcx).ty,
                 mpi,
             );
diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
index 00bfb5e6600..50637e2ac03 100644
--- a/compiler/rustc_mir_transform/src/required_consts.rs
+++ b/compiler/rustc_mir_transform/src/required_consts.rs
@@ -1,14 +1,23 @@
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{ConstOperand, Location};
+use rustc_middle::mir::{traversal, Body, ConstOperand, Location};
 
 pub struct RequiredConstsVisitor<'a, 'tcx> {
     required_consts: &'a mut Vec<ConstOperand<'tcx>>,
 }
 
 impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
-    pub fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self {
+    fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self {
         RequiredConstsVisitor { required_consts }
     }
+
+    pub fn compute_required_consts(body: &mut Body<'tcx>) {
+        let mut required_consts = Vec::new();
+        let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
+        for (bb, bb_data) in traversal::reverse_postorder(&body) {
+            required_consts_visitor.visit_basic_block_data(bb, bb_data);
+        }
+        body.set_required_consts(required_consts);
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index d2f50040821..29185e79bce 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -1,26 +1,27 @@
+use std::assert_matches::assert_matches;
+use std::{fmt, iter};
+
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::{Idx, IndexVec};
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::ty::{
+    self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt,
+};
 use rustc_middle::{bug, span_bug};
-use rustc_span::{source_map::Spanned, Span, DUMMY_SP};
+use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
+use rustc_span::source_map::Spanned;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 use rustc_target::spec::abi::Abi;
 
-use std::assert_matches::assert_matches;
-use std::fmt;
-use std::iter;
-
 use crate::{
     abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
     instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify,
 };
-use rustc_middle::mir::patch::MirPatch;
-use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
 
 mod async_destructor_ctor;
 
@@ -154,7 +155,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
             &deref_separator::Derefer,
             &remove_noop_landing_pads::RemoveNoopLandingPads,
             &simplify::SimplifyCfg::MakeShim,
-            &instsimplify::InstSimplify,
+            &instsimplify::InstSimplify::BeforeInline,
             &abort_unwinding_calls::AbortUnwindingCalls,
             &add_call_guards::CriticalCallEdges,
         ],
@@ -304,7 +305,7 @@ fn new_body<'tcx>(
     arg_count: usize,
     span: Span,
 ) -> Body<'tcx> {
-    Body::new(
+    let mut body = Body::new(
         source,
         basic_blocks,
         IndexVec::from_elem_n(
@@ -325,7 +326,10 @@ fn new_body<'tcx>(
         None,
         // FIXME(compiler-errors): is this correct?
         None,
-    )
+    );
+    // Shims do not directly mention any consts.
+    body.set_required_consts(Vec::new());
+    body
 }
 
 pub struct DropShimElaborator<'a, 'tcx> {
@@ -968,13 +972,16 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
     };
 
     let source = MirSource::item(ctor_id);
-    let body = new_body(
+    let mut body = new_body(
         source,
         IndexVec::from_elem_n(start_block, 1),
         local_decls,
         sig.inputs().len(),
         span,
     );
+    // A constructor doesn't mention any other items (and we don't run the usual optimization passes
+    // so this would otherwise not get filled).
+    body.set_mentioned_items(Vec::new());
 
     crate::pass_manager::dump_mir_for_phase_change(tcx, &body);
 
@@ -989,7 +996,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
 /// }
 /// ```
 fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
-    assert!(matches!(self_ty.kind(), ty::FnPtr(..)), "expected fn ptr, found {self_ty}");
+    assert_matches!(self_ty.kind(), ty::FnPtr(..), "expected fn ptr, found {self_ty}");
     let span = tcx.def_span(def_id);
     let Some(sig) = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]).no_bound_vars() else {
         span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index e174cccdad6..59f67d8e73f 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -1,14 +1,14 @@
 use std::iter;
 
-use super::MirPass;
-use rustc_middle::{
-    bug,
-    mir::{
-        interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
-        StatementKind, SwitchTargets, TerminatorKind,
-    },
-    ty::{Ty, TyCtxt},
+use rustc_middle::bug;
+use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::{
+    BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, StatementKind, SwitchTargets,
+    TerminatorKind,
 };
+use rustc_middle::ty::{Ty, TyCtxt};
+
+use super::MirPass;
 
 /// Pass to convert `if` conditions on integrals into switches on the integral.
 /// For an example, it turns something like
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index 93736e55996..35cb6872fe9 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -1,4 +1,5 @@
-use rustc_index::{bit_set::BitSet, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 1404a45f4d2..81baf58a5e0 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -1,6 +1,5 @@
 //! A pass that eliminates branches on uninhabited or unreachable enum variants.
 
-use crate::MirPass;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::mir::patch::MirPatch;
@@ -12,6 +11,8 @@ use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::{Abi, Variants};
 
+use crate::MirPass;
+
 pub struct UnreachableEnumBranching;
 
 fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option<Local> {
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index ab5c25c4937..491ae1c0d08 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -17,9 +17,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{Size, FIRST_VARIANT};
 use rustc_target::spec::abi::Abi;
 
-use crate::util::is_within_packed;
-
-use crate::util::relate_types;
+use crate::util::{is_within_packed, relate_types};
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum EdgeKind {
@@ -900,8 +898,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         self.param_env,
                         adt_def.non_enum_variant().fields[field].ty(self.tcx, args),
                     );
-                    if fields.len() == 1 {
-                        let src_ty = fields.raw[0].ty(self.body, self.tcx);
+                    if let [field] = fields.raw.as_slice() {
+                        let src_ty = field.ty(self.body, self.tcx);
                         if !self.mir_assign_valid_types(src_ty, dest_ty) {
                             self.fail(location, "union field has the wrong type");
                         }
@@ -969,11 +967,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         self.fail(location, "RawPtr should be in runtime MIR only");
                     }
 
-                    if fields.len() != 2 {
-                        self.fail(location, "raw pointer aggregate must have 2 fields");
-                    } else {
-                        let data_ptr_ty = fields.raw[0].ty(self.body, self.tcx);
-                        let metadata_ty = fields.raw[1].ty(self.body, self.tcx);
+                    if let [data_ptr, metadata] = fields.raw.as_slice() {
+                        let data_ptr_ty = data_ptr.ty(self.body, self.tcx);
+                        let metadata_ty = metadata.ty(self.body, self.tcx);
                         if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() {
                             if *in_mut != mutability {
                                 self.fail(location, "input and output mutability must match");
@@ -1000,6 +996,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                 self.fail(location, "metadata for pointer-to-thin must be unit");
                             }
                         }
+                    } else {
+                        self.fail(location, "raw pointer aggregate must have 2 fields");
                     }
                 }
             },
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 3655a677ba0..0ae635f9b73 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -207,6 +207,9 @@
 
 mod move_check;
 
+use std::path::PathBuf;
+
+use move_check::MoveCheckState;
 use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
@@ -216,17 +219,15 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
-use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::Visitor as MirVisitor;
-use rustc_middle::mir::{self, Location, MentionedItem};
+use rustc_middle::mir::{self, traversal, Location, MentionedItem};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
-use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{
-    self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
-    TypeVisitableExt, VtblEntry,
+    self, AssocKind, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt,
+    TypeFoldable, TypeVisitableExt, VtblEntry,
 };
 use rustc_middle::util::Providers;
 use rustc_middle::{bug, span_bug};
@@ -236,11 +237,9 @@ use rustc_span::source_map::{dummy_spanned, respan, Spanned};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::Size;
-use std::path::PathBuf;
 use tracing::{debug, instrument, trace};
 
 use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit};
-use move_check::MoveCheckState;
 
 #[derive(PartialEq)]
 pub enum MonoItemCollectionStrategy {
@@ -1020,7 +1019,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
             if ty.is_sized(tcx.tcx, param_env) {
                 return false;
             }
-            let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);
+            let tail = tcx.struct_tail_for_codegen(ty, param_env);
             match tail.kind() {
                 ty::Foreign(..) => false,
                 ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
@@ -1030,7 +1029,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
         if type_has_metadata(inner_source) {
             (inner_source, inner_target)
         } else {
-            tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env)
+            tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, param_env)
         }
     };
 
@@ -1230,7 +1229,7 @@ fn collect_items_of_instance<'tcx>(
 
     // Always visit all `required_consts`, so that we evaluate them and abort compilation if any of
     // them errors.
-    for const_op in &body.required_consts {
+    for const_op in body.required_consts() {
         if let Some(val) = collector.eval_constant(const_op) {
             collect_const_value(tcx, val, mentioned_items);
         }
@@ -1238,7 +1237,7 @@ fn collect_items_of_instance<'tcx>(
 
     // Always gather mentioned items. We try to avoid processing items that we have already added to
     // `used_items` above.
-    for item in &body.mentioned_items {
+    for item in body.mentioned_items() {
         if !collector.used_mentioned_items.contains(&item.node) {
             let item_mono = collector.monomorphize(item.node);
             visit_mentioned_item(tcx, &item_mono, item.span, mentioned_items);
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index 9548c46e6fa..88286cb73a6 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -1,10 +1,11 @@
 use std::path::PathBuf;
 
-use crate::fluent_generated as fluent;
 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
 use rustc_macros::{Diagnostic, LintDiagnostic};
 use rustc_span::{Span, Symbol};
 
+use crate::fluent_generated as fluent;
+
 #[derive(Diagnostic)]
 #[diag(monomorphize_recursion_limit)]
 pub struct RecursionLimit {
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 3b8f0a91e74..d6b0f9c4d28 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -3,12 +3,11 @@
 // tidy-alphabetical-end
 
 use rustc_hir::lang_items::LangItem;
-use rustc_middle::bug;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::traits;
 use rustc_middle::ty::adjustment::CustomCoerceUnsized;
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::util::Providers;
+use rustc_middle::{bug, traits};
 use rustc_span::ErrorGuaranteed;
 
 mod collector;
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 8c7c5e0074a..65a3d8d1742 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -113,15 +113,15 @@ use rustc_middle::mir::mono::{
     Visibility,
 };
 use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths};
-use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt};
+use rustc_middle::ty::visit::TypeVisitableExt;
+use rustc_middle::ty::{self, InstanceKind, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
 use rustc_session::CodegenUnits;
 use rustc_span::symbol::Symbol;
 use tracing::debug;
 
-use crate::collector::UsageMap;
-use crate::collector::{self, MonoItemCollectionStrategy};
+use crate::collector::{self, MonoItemCollectionStrategy, UsageMap};
 use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode};
 
 struct PartitioningCx<'a, 'tcx> {
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 2d69bfa4da8..5a24202db65 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -5,18 +5,14 @@
 //! generic parameters are unused (and eventually, in what ways generic parameters are used - only
 //! for their size, offset of a field, etc.).
 
-use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
-use rustc_middle::mir::{
-    self,
-    visit::{TyContext, Visitor},
-    Local, LocalDecl, Location,
-};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::ConstContext;
+use rustc_middle::mir::visit::{TyContext, Visitor};
+use rustc_middle::mir::{self, Local, LocalDecl, Location};
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{
-    self,
-    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor},
-    GenericArgsRef, Ty, TyCtxt, UnusedGenericParams,
-};
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams};
 use rustc_span::symbol::sym;
 use tracing::{debug, instrument};
 
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index e25c5c9f27c..093a697beeb 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -1,7 +1,8 @@
-use rustc_middle::ty::{self, ClosureSizeProfileData, Instance, TyCtxt};
 use std::fs::OpenOptions;
 use std::io::prelude::*;
 
+use rustc_middle::ty::{self, ClosureSizeProfileData, Instance, TyCtxt};
+
 /// For a given closure, writes out the data for the profiling the impact of RFC 2229 on
 /// closure size into a CSV.
 ///
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
index 254ee514f8b..132b7400300 100644
--- a/compiler/rustc_next_trait_solver/src/resolve.rs
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -1,9 +1,10 @@
-use crate::delegate::SolverDelegate;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::TypeVisitableExt;
 use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 
+use crate::delegate::SolverDelegate;
+
 ///////////////////////////////////////////////////////////////////////////
 // EAGER RESOLUTION
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index f74597fcb39..84921e87fb3 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -3,12 +3,11 @@
 pub(super) mod structural_traits;
 
 use derive_where::derive_where;
-use rustc_type_ir::elaborate;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::visit::TypeVisitableExt as _;
-use rustc_type_ir::{self as ty, Interner, Upcast as _};
+use rustc_type_ir::{self as ty, elaborate, Interner, Upcast as _};
 use tracing::{debug, instrument};
 
 use crate::delegate::SolverDelegate;
@@ -699,6 +698,18 @@ where
                 if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
                     Err(NoSolution)
                 } else {
+                    // While the trait bound itself may be unknowable, we may be able to
+                    // prove that a super trait is not implemented. For this, we recursively
+                    // prove the super trait bounds of the current goal.
+                    //
+                    // We skip the goal itself as that one would cycle.
+                    let predicate: I::Predicate = trait_ref.upcast(cx);
+                    ecx.add_goals(
+                        GoalSource::Misc,
+                        elaborate::elaborate(cx, [predicate])
+                            .skip(1)
+                            .map(|predicate| goal.with(cx, predicate)),
+                    );
                     ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                 }
             },
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 60beaa0df84..00837f7cdd8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -7,7 +7,7 @@ use rustc_type_ir::data_structures::HashMap;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::{self as ty, Interner, Upcast as _};
+use rustc_type_ir::{self as ty, elaborate, Interner, Upcast as _};
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::instrument;
 
@@ -458,28 +458,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
             ))
         }
 
-        ty::FnDef(..) | ty::FnPtr(..) => {
-            let bound_sig = self_ty.fn_sig(cx);
-            let sig = bound_sig.skip_binder();
-            let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future);
-            // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
-            // return type implements `Future`.
-            let nested = vec![
-                bound_sig
-                    .rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()]))
-                    .upcast(cx),
-            ];
-            let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput);
-            let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]);
-            Ok((
-                bound_sig.rebind(AsyncCallableRelevantTypes {
-                    tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
-                    output_coroutine_ty: sig.output(),
-                    coroutine_return_ty: future_output_ty,
-                }),
-                nested,
-            ))
+        ty::FnDef(def_id, _) => {
+            let sig = self_ty.fn_sig(cx);
+            if sig.skip_binder().is_fn_trait_compatible() && !cx.has_target_features(def_id) {
+                fn_item_to_async_callable(cx, sig)
+            } else {
+                Err(NoSolution)
+            }
+        }
+        ty::FnPtr(..) => {
+            let sig = self_ty.fn_sig(cx);
+            if sig.skip_binder().is_fn_trait_compatible() {
+                fn_item_to_async_callable(cx, sig)
+            } else {
+                Err(NoSolution)
+            }
         }
+
         ty::Closure(_, args) => {
             let args = args.as_closure();
             let bound_sig = args.sig();
@@ -563,6 +558,29 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
     }
 }
 
+fn fn_item_to_async_callable<I: Interner>(
+    cx: I,
+    bound_sig: ty::Binder<I, ty::FnSig<I>>,
+) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
+    let sig = bound_sig.skip_binder();
+    let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future);
+    // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
+    // return type implements `Future`.
+    let nested = vec![
+        bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])).upcast(cx),
+    ];
+    let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput);
+    let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]);
+    Ok((
+        bound_sig.rebind(AsyncCallableRelevantTypes {
+            tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
+            output_coroutine_ty: sig.output(),
+            coroutine_return_ty: future_output_ty,
+        }),
+        nested,
+    ))
+}
+
 /// Given a coroutine-closure, project to its returned coroutine when we are *certain*
 /// that the closure's kind is compatible with the goal.
 fn coroutine_closure_to_certain_coroutine<I: Interner>(
@@ -671,11 +689,19 @@ where
 {
     let cx = ecx.cx();
     let mut requirements = vec![];
-    requirements.extend(
+    // Elaborating all supertrait outlives obligations here is not soundness critical,
+    // since if we just used the unelaborated set, then the transitive supertraits would
+    // be reachable when proving the former. However, since we elaborate all supertrait
+    // outlives obligations when confirming impls, we would end up with a different set
+    // of outlives obligations here if we didn't do the same, leading to ambiguity.
+    // FIXME(-Znext-solver=coinductive): Adding supertraits here can be removed once we
+    // make impls coinductive always, since they'll always need to prove their supertraits.
+    requirements.extend(elaborate::elaborate(
+        cx,
         cx.explicit_super_predicates_of(trait_ref.def_id)
             .iter_instantiated(cx, trait_ref.args)
             .map(|(pred, _)| pred),
-    );
+    ));
 
     // FIXME(associated_const_equality): Also add associated consts to
     // the requirements here.
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 9474d501d6f..2e521ddcec3 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -21,9 +21,8 @@ use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
 use crate::delegate::SolverDelegate;
 use crate::resolve::EagerResolver;
 use crate::solve::eval_ctxt::NestedGoals;
-use crate::solve::inspect;
 use crate::solve::{
-    response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt,
+    inspect, response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt,
     ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution,
     PredefinedOpaquesData, QueryInput, QueryResult, Response,
 };
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
index 4258dd9263a..e459d5cbe58 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
@@ -5,8 +5,9 @@ use tracing::instrument;
 
 use crate::delegate::SolverDelegate;
 use crate::solve::assembly::Candidate;
-use crate::solve::inspect;
-use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult};
+use crate::solve::{
+    inspect, BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult,
+};
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T>
 where
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 36e13cc97d6..a3c21666bd6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
@@ -13,10 +13,9 @@ use rustc_type_ir::{self as ty, search_graph, Interner};
 
 use crate::delegate::SolverDelegate;
 use crate::solve::eval_ctxt::canonical;
-use crate::solve::inspect;
 use crate::solve::{
-    CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput,
-    QueryResult,
+    inspect, CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource,
+    QueryInput, QueryResult,
 };
 
 /// The core data structure when building proof trees.
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index a83bd689a80..5738173c7a8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -6,8 +6,7 @@ mod weak_types;
 use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::Upcast as _;
-use rustc_type_ir::{self as ty, Interner, NormalizesTo};
+use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
 use tracing::instrument;
 
 use crate::delegate::SolverDelegate;
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 4474bbc2351..b1dba712f79 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -87,6 +87,19 @@ where
                 .map(|pred| goal.with(cx, pred));
             ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
 
+            // We currently elaborate all supertrait outlives obligations from impls.
+            // This can be removed when we actually do coinduction correctly, and prove
+            // all supertrait obligations unconditionally.
+            let goal_clause: I::Clause = goal.predicate.upcast(cx);
+            for clause in elaborate::elaborate(cx, [goal_clause]) {
+                if matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
+                ) {
+                    ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
+                }
+            }
+
             ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
         })
     }
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 391a5791776..8e8d91ce4d0 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -66,7 +66,7 @@ parse_box_not_pat = expected pattern, found {$descr}
     .suggestion = escape `box` to use it as an identifier
 
 parse_box_syntax_removed = `box_syntax` has been removed
-    .suggestion = use `Box::new()` instead
+parse_box_syntax_removed_suggestion = use `Box::new()` instead
 
 parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
 
@@ -365,6 +365,7 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment
     .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
 
 parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
+    .label = this is not an unsafe attribute
     .suggestion = remove the `unsafe(...)`
     .note = extraneous unsafe is not allowed in attributes
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 2e81d2a876b..0d4512be480 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2,9 +2,10 @@ use std::borrow::Cow;
 
 use rustc_ast::token::Token;
 use rustc_ast::{Path, Visibility};
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
-    SubdiagMessageOp, Subdiagnostic,
+    Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp,
+    Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::errors::ExprParenthesesNeeded;
@@ -554,12 +555,7 @@ pub(crate) enum MissingInInForLoopSub {
         code = "in"
     )]
     InNotOf(#[primary_span] Span),
-    #[suggestion(
-        parse_add_in,
-        style = "verbose",
-        applicability = "maybe-incorrect",
-        code = " in "
-    )]
+    #[suggestion(parse_add_in, style = "verbose", applicability = "maybe-incorrect", code = " in ")]
     AddIn(#[primary_span] Span),
 }
 
@@ -2729,15 +2725,24 @@ impl HelpUseLatestEdition {
 
 #[derive(Diagnostic)]
 #[diag(parse_box_syntax_removed)]
-pub struct BoxSyntaxRemoved<'a> {
+pub struct BoxSyntaxRemoved {
     #[primary_span]
-    #[suggestion(
-        code = "Box::new({code})",
-        applicability = "machine-applicable",
-        style = "verbose"
-    )]
     pub span: Span,
-    pub code: &'a str,
+    #[subdiagnostic]
+    pub sugg: AddBoxNew,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parse_box_syntax_removed_suggestion,
+    applicability = "machine-applicable",
+    style = "verbose"
+)]
+pub struct AddBoxNew {
+    #[suggestion_part(code = "Box::new(")]
+    pub box_kw_and_lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
 }
 
 #[derive(Diagnostic)]
@@ -3187,6 +3192,7 @@ pub(crate) struct DotDotRangeAttribute {
 #[note]
 pub struct InvalidAttrUnsafe {
     #[primary_span]
+    #[label]
     pub span: Span,
     pub name: Path,
 }
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index 1247e2e44fb..4d5d1ce099e 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -1,9 +1,10 @@
-use super::UnmatchedDelim;
 use rustc_ast::token::Delimiter;
 use rustc_errors::Diag;
 use rustc_span::source_map::SourceMap;
 use rustc_span::Span;
 
+use super::UnmatchedDelim;
+
 #[derive(Default)]
 pub(super) struct TokenTreeDiagInfo {
     /// Stack of open delimiters and their spans. Used for error message.
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 511805cf8d6..f30939093c2 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,25 +1,26 @@
 use std::ops::Range;
 
-use crate::errors;
-use crate::lexer::unicode_chars::UNICODE_ARRAY;
-use crate::make_unclosed_delims_error;
 use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
-use rustc_errors::{codes::*, Applicability, Diag, DiagCtxtHandle, StashKey};
+use rustc_errors::codes::*;
+use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
 use rustc_lexer::unescape::{self, EscapeError, Mode};
-use rustc_lexer::{Base, DocStyle, RawStrError};
-use rustc_lexer::{Cursor, LiteralKind};
+use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError};
 use rustc_session::lint::builtin::{
     RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
 };
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::ParseSess;
+use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-use rustc_span::{edition::Edition, BytePos, Pos, Span};
+use rustc_span::{BytePos, Pos, Span};
 use tracing::debug;
 
+use crate::lexer::unicode_chars::UNICODE_ARRAY;
+use crate::{errors, make_unclosed_delims_error};
+
 mod diagnostics;
 mod tokentrees;
 mod unescape_error_reporting;
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 8e543454691..fb4ed5b93b2 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -1,14 +1,15 @@
-use super::diagnostics::report_suspicious_mismatch_block;
-use super::diagnostics::same_indentation_level;
-use super::diagnostics::TokenTreeDiagInfo;
-use super::{StringReader, UnmatchedDelim};
-use crate::Parser;
 use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust::token_to_string;
 use rustc_errors::{Applicability, PErr};
 use rustc_span::symbol::kw;
 
+use super::diagnostics::{
+    report_suspicious_mismatch_block, same_indentation_level, TokenTreeDiagInfo,
+};
+use super::{StringReader, UnmatchedDelim};
+use crate::Parser;
+
 pub(super) struct TokenTreesReader<'psess, 'src> {
     string_reader: StringReader<'psess, 'src>,
     /// The "next" token, which has been obtained from the `StringReader` but
@@ -72,16 +73,31 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
     fn eof_err(&mut self) -> PErr<'psess> {
         let msg = "this file contains an unclosed delimiter";
         let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
-        for &(_, sp) in &self.diag_info.open_braces {
-            err.span_label(sp, "unclosed delimiter");
+
+        let unclosed_delimiter_show_limit = 5;
+        let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len());
+        for &(_, span) in &self.diag_info.open_braces[..len] {
+            err.span_label(span, "unclosed delimiter");
             self.diag_info.unmatched_delims.push(UnmatchedDelim {
                 found_delim: None,
                 found_span: self.token.span,
-                unclosed_span: Some(sp),
+                unclosed_span: Some(span),
                 candidate_span: None,
             });
         }
 
+        if let Some((_, span)) = self.diag_info.open_braces.get(unclosed_delimiter_show_limit)
+            && self.diag_info.open_braces.len() >= unclosed_delimiter_show_limit + 2
+        {
+            err.span_label(
+                *span,
+                format!(
+                    "another {} unclosed delimiters begin from here",
+                    self.diag_info.open_braces.len() - unclosed_delimiter_show_limit
+                ),
+            );
+        }
+
         if let Some((delim, _)) = self.diag_info.open_braces.last() {
             report_suspicious_mismatch_block(
                 &mut err,
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index b7a790fcf83..efa53f0962b 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -40,7 +40,8 @@ pub(crate) fn emit_unescape_error(
             dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false })
         }
         EscapeError::MoreThanOneChar => {
-            use unicode_normalization::{char::is_combining_mark, UnicodeNormalization};
+            use unicode_normalization::char::is_combining_mark;
+            use unicode_normalization::UnicodeNormalization;
             let mut sugg = None;
             let mut note = None;
 
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 0a82ede3b75..d78b3664b1e 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -1,12 +1,12 @@
 //! Characters and their corresponding confusables were collected from
 //! <https://www.unicode.org/Public/security/10.0.0/confusables.txt>
 
+use rustc_span::symbol::kw;
+use rustc_span::{BytePos, Pos, Span};
+
 use super::StringReader;
-use crate::{
-    errors::TokenSubstitution,
-    token::{self, Delimiter},
-};
-use rustc_span::{symbol::kw, BytePos, Pos, Span};
+use crate::errors::TokenSubstitution;
+use crate::token::{self, Delimiter};
 
 #[rustfmt::skip] // for line breaks
 pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 4454747ea02..37079271493 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -5,6 +5,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(array_windows)]
+#![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(debug_closure_helpers)]
 #![feature(if_let_guard)]
@@ -12,18 +13,17 @@
 #![feature(let_chains)]
 // tidy-alphabetical-end
 
+use std::path::Path;
+
 use rustc_ast as ast;
-use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{AttrItem, Attribute, MetaItem};
+use rustc_ast::{token, AttrItem, Attribute, MetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diag, FatalError, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::{FileName, SourceFile, Span};
 
-use std::path::Path;
-
 pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
 
 #[macro_use]
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 535b53a836e..8fdfbcee385 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,16 +1,16 @@
-use crate::errors;
-use crate::fluent_generated as fluent;
-use crate::maybe_whole;
-
-use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Delimiter};
-use rustc_errors::{codes::*, Diag, PResult};
-use rustc_span::{sym, symbol::kw, BytePos, Span};
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, PResult};
+use rustc_span::symbol::kw;
+use rustc_span::{sym, BytePos, Span};
 use thin_vec::ThinVec;
 use tracing::debug;
 
+use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle};
+use crate::{errors, fluent_generated as fluent, maybe_whole};
+
 // Public for rustfmt usage
 #[derive(Debug)]
 pub enum InnerAttrPolicy {
@@ -31,6 +31,12 @@ enum OuterAttributeType {
     Attribute,
 }
 
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum AllowLeadingUnsafe {
+    Yes,
+    No,
+}
+
 impl<'a> Parser<'a> {
     /// Parses attributes that appear before an item.
     pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
@@ -307,8 +313,8 @@ impl<'a> Parser<'a> {
                 // inner attribute, for possible later processing in a `LazyAttrTokenStream`.
                 if let Capturing::Yes = self.capture_state.capturing {
                     let end_pos = self.num_bump_calls;
-                    let range = start_pos..end_pos;
-                    self.capture_state.inner_attr_ranges.insert(attr.id, range);
+                    let parser_range = ParserRange(start_pos..end_pos);
+                    self.capture_state.inner_attr_parser_ranges.insert(attr.id, parser_range);
                 }
                 attrs.push(attr);
             } else {
@@ -332,7 +338,7 @@ impl<'a> Parser<'a> {
 
     /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
     pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
-        let cfg_predicate = self.parse_meta_item()?;
+        let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
         self.expect(&token::Comma)?;
 
         // Presumably, the majority of the time there will only be one attr.
@@ -368,7 +374,10 @@ impl<'a> Parser<'a> {
     /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
     /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
     /// ```
-    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
+    pub fn parse_meta_item(
+        &mut self,
+        unsafe_allowed: AllowLeadingUnsafe,
+    ) -> PResult<'a, ast::MetaItem> {
         // We can't use `maybe_whole` here because it would bump in the `None`
         // case, which we don't want.
         if let token::Interpolated(nt) = &self.token.kind
@@ -384,7 +393,11 @@ impl<'a> Parser<'a> {
         }
 
         let lo = self.token.span;
-        let is_unsafe = self.eat_keyword(kw::Unsafe);
+        let is_unsafe = if unsafe_allowed == AllowLeadingUnsafe::Yes {
+            self.eat_keyword(kw::Unsafe)
+        } else {
+            false
+        };
         let unsafety = if is_unsafe {
             let unsafe_span = self.prev_token.span;
             self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
@@ -427,7 +440,7 @@ impl<'a> Parser<'a> {
             Err(err) => err.cancel(), // we provide a better error below
         }
 
-        match self.parse_meta_item() {
+        match self.parse_meta_item(AllowLeadingUnsafe::No) {
             Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
             Err(err) => err.cancel(), // we provide a better error below
         }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 5dc49ea51d1..abf61036c2d 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,14 +1,19 @@
-use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor};
+use std::{iter, mem};
+
 use rustc_ast::token::{Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing};
-use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream};
-use rustc_ast::{self as ast};
-use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens};
+use rustc_ast::tokenstream::{
+    AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream,
+    Spacing, ToAttrTokenStream,
+};
+use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, HasTokens};
 use rustc_errors::PResult;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Span, DUMMY_SP};
 
-use std::{iter, mem};
+use super::{
+    Capturing, FlatToken, ForceCollect, NodeRange, NodeReplacement, Parser, ParserRange,
+    TokenCursor,
+};
 
 /// A wrapper type to ensure that the parser handles outer attributes correctly.
 /// When we parse outer attributes, we need to ensure that we capture tokens
@@ -26,8 +31,8 @@ use std::{iter, mem};
 #[derive(Debug, Clone)]
 pub struct AttrWrapper {
     attrs: AttrVec,
-    // The start of the outer attributes in the token cursor.
-    // This allows us to create a `ReplaceRange` for the entire attribute
+    // The start of the outer attributes in the parser's token stream.
+    // This lets us create a `NodeReplacement` for the entire attribute
     // target, including outer attributes.
     start_pos: u32,
 }
@@ -51,10 +56,9 @@ impl AttrWrapper {
 
     /// Prepend `self.attrs` to `attrs`.
     // FIXME: require passing an NT to prevent misuse of this method
-    pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
-        let mut self_attrs = self.attrs;
-        mem::swap(attrs, &mut self_attrs);
-        attrs.extend(self_attrs);
+    pub(crate) fn prepend_to_nt_inner(mut self, attrs: &mut AttrVec) {
+        mem::swap(attrs, &mut self.attrs);
+        attrs.extend(self.attrs);
     }
 
     pub fn is_empty(&self) -> bool {
@@ -87,7 +91,7 @@ struct LazyAttrTokenStreamImpl {
     cursor_snapshot: TokenCursor,
     num_calls: u32,
     break_last_token: bool,
-    replace_ranges: Box<[ReplaceRange]>,
+    node_replacements: Box<[NodeReplacement]>,
 }
 
 impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
@@ -102,21 +106,24 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
             .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next())))
             .take(self.num_calls as usize);
 
-        if self.replace_ranges.is_empty() {
+        if self.node_replacements.is_empty() {
             make_attr_token_stream(tokens, self.break_last_token)
         } else {
             let mut tokens: Vec<_> = tokens.collect();
-            let mut replace_ranges = self.replace_ranges.to_vec();
-            replace_ranges.sort_by_key(|(range, _)| range.start);
+            let mut node_replacements = self.node_replacements.to_vec();
+            node_replacements.sort_by_key(|(range, _)| range.0.start);
 
             #[cfg(debug_assertions)]
-            for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() {
+            for [(node_range, tokens), (next_node_range, next_tokens)] in
+                node_replacements.array_windows()
+            {
                 assert!(
-                    range.end <= next_range.start || range.end >= next_range.end,
-                    "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
-                    range,
+                    node_range.0.end <= next_node_range.0.start
+                        || node_range.0.end >= next_node_range.0.end,
+                    "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
+                    node_range,
                     tokens,
-                    next_range,
+                    next_node_range,
                     next_tokens,
                 );
             }
@@ -134,20 +141,23 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
             // start position, we ensure that any (outer) replace range which
             // encloses another (inner) replace range will fully overwrite the
             // inner range's replacement.
-            for (range, target) in replace_ranges.into_iter().rev() {
-                assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}");
+            for (node_range, target) in node_replacements.into_iter().rev() {
+                assert!(
+                    !node_range.0.is_empty(),
+                    "Cannot replace an empty node range: {:?}",
+                    node_range.0
+                );
 
                 // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus
                 // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the
                 // total length of `tokens` constant throughout the replacement process, allowing
-                // us to use all of the `ReplaceRanges` entries without adjusting indices.
+                // us to do all replacements without adjusting indices.
                 let target_len = target.is_some() as usize;
                 tokens.splice(
-                    (range.start as usize)..(range.end as usize),
-                    target
-                        .into_iter()
-                        .map(|target| FlatToken::AttrsTarget(target))
-                        .chain(iter::repeat(FlatToken::Empty).take(range.len() - target_len)),
+                    (node_range.0.start as usize)..(node_range.0.end as usize),
+                    target.into_iter().map(|target| FlatToken::AttrsTarget(target)).chain(
+                        iter::repeat(FlatToken::Empty).take(node_range.0.len() - target_len),
+                    ),
                 );
             }
             make_attr_token_stream(tokens.into_iter(), self.break_last_token)
@@ -214,7 +224,7 @@ impl<'a> Parser<'a> {
         let cursor_snapshot = self.token_cursor.clone();
         let start_pos = self.num_bump_calls;
         let has_outer_attrs = !attrs.attrs.is_empty();
-        let replace_ranges_start = self.capture_state.replace_ranges.len();
+        let parser_replacements_start = self.capture_state.parser_replacements.len();
 
         // We set and restore `Capturing::Yes` on either side of the call to
         // `f`, so we can distinguish the outermost call to
@@ -269,7 +279,7 @@ impl<'a> Parser<'a> {
             return Ok(ret);
         }
 
-        let replace_ranges_end = self.capture_state.replace_ranges.len();
+        let parser_replacements_end = self.capture_state.parser_replacements.len();
 
         assert!(
             !(self.break_last_token && capture_trailing),
@@ -286,15 +296,16 @@ impl<'a> Parser<'a> {
 
         let num_calls = end_pos - start_pos;
 
-        // Take the captured ranges for any inner attributes that we parsed in
-        // `Parser::parse_inner_attributes`, and pair them in a `ReplaceRange`
-        // with `None`, which means the relevant tokens will be removed. (More
-        // details below.)
-        let mut inner_attr_replace_ranges = Vec::new();
+        // Take the captured `ParserRange`s for any inner attributes that we parsed in
+        // `Parser::parse_inner_attributes`, and pair them in a `ParserReplacement` with `None`,
+        // which means the relevant tokens will be removed. (More details below.)
+        let mut inner_attr_parser_replacements = Vec::new();
         for attr in ret.attrs() {
             if attr.style == ast::AttrStyle::Inner {
-                if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&attr.id) {
-                    inner_attr_replace_ranges.push((attr_range, None));
+                if let Some(inner_attr_parser_range) =
+                    self.capture_state.inner_attr_parser_ranges.remove(&attr.id)
+                {
+                    inner_attr_parser_replacements.push((inner_attr_parser_range, None));
                 } else {
                     self.dcx().span_delayed_bug(attr.span, "Missing token range for attribute");
                 }
@@ -303,37 +314,41 @@ impl<'a> Parser<'a> {
 
         // This is hot enough for `deep-vector` that checking the conditions for an empty iterator
         // is measurably faster than actually executing the iterator.
-        let replace_ranges: Box<[ReplaceRange]> =
-            if replace_ranges_start == replace_ranges_end && inner_attr_replace_ranges.is_empty() {
-                Box::new([])
-            } else {
-                // Grab any replace ranges that occur *inside* the current AST node. We will
-                // perform the actual replacement only when we convert the `LazyAttrTokenStream` to
-                // an `AttrTokenStream`.
-                self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
-                    .iter()
-                    .cloned()
-                    .chain(inner_attr_replace_ranges.iter().cloned())
-                    .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data))
-                    .collect()
-            };
+        let node_replacements: Box<[_]> = if parser_replacements_start == parser_replacements_end
+            && inner_attr_parser_replacements.is_empty()
+        {
+            Box::new([])
+        } else {
+            // Grab any replace ranges that occur *inside* the current AST node. Convert them
+            // from `ParserRange` form to `NodeRange` form. We will perform the actual
+            // replacement only when we convert the `LazyAttrTokenStream` to an
+            // `AttrTokenStream`.
+            self.capture_state.parser_replacements
+                [parser_replacements_start..parser_replacements_end]
+                .iter()
+                .cloned()
+                .chain(inner_attr_parser_replacements.iter().cloned())
+                .map(|(parser_range, data)| (NodeRange::new(parser_range, start_pos), data))
+                .collect()
+        };
 
         // What is the status here when parsing the example code at the top of this method?
         //
         // When parsing `g`:
         // - `start_pos..end_pos` is `12..33` (`fn g { ... }`, excluding the outer attr).
-        // - `inner_attr_replace_ranges` has one entry (`5..15`, when counting from `fn`), to
+        // - `inner_attr_parser_replacements` has one entry (`ParserRange(17..27)`), to
         //   delete the inner attr's tokens.
-        //   - This entry is put into the lazy tokens for `g`, i.e. deleting the inner attr from
-        //     those tokens (if they get evaluated).
+        //   - This entry is converted to `NodeRange(5..15)` (relative to the `fn`) and put into
+        //     the lazy tokens for `g`, i.e. deleting the inner attr from those tokens (if they get
+        //     evaluated).
         //   - Those lazy tokens are also put into an `AttrsTarget` that is appended to `self`'s
         //     replace ranges at the bottom of this function, for processing when parsing `m`.
-        // - `replace_ranges_start..replace_ranges_end` is empty.
+        // - `parser_replacements_start..parser_replacements_end` is empty.
         //
         // When parsing `m`:
         // - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute).
-        // - `inner_attr_replace_ranges` is empty.
-        // - `replace_range_start..replace_ranges_end` has one entry.
+        // - `inner_attr_parser_replacements` is empty.
+        // - `parser_replacements_start..parser_replacements_end` has one entry.
         //   - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`,
         //     including its outer attribute), with:
         //     - `attrs`: includes the outer and the inner attr.
@@ -344,7 +359,7 @@ impl<'a> Parser<'a> {
             num_calls,
             cursor_snapshot,
             break_last_token: self.break_last_token,
-            replace_ranges,
+            node_replacements,
         });
 
         // If we support tokens and don't already have them, store the newly captured tokens.
@@ -365,7 +380,7 @@ impl<'a> Parser<'a> {
             // What is the status here when parsing the example code at the top of this method?
             //
             // When parsing `g`, we add one entry:
-            // - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with:
+            // - The pushed entry (`ParserRange(3..33)`) has a new `AttrsTarget` with:
             //   - `attrs`: includes the outer and the inner attr.
             //   - `tokens`: lazy tokens for `g` (with its inner attr deleted).
             //
@@ -376,12 +391,14 @@ impl<'a> Parser<'a> {
             // cfg-expand this AST node.
             let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos };
             let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens };
-            self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target)));
+            self.capture_state
+                .parser_replacements
+                .push((ParserRange(start_pos..end_pos), Some(target)));
         } else if matches!(self.capture_state.capturing, Capturing::No) {
             // Only clear the ranges once we've finished capturing entirely, i.e. we've finished
             // the outermost call to this method.
-            self.capture_state.replace_ranges.clear();
-            self.capture_state.inner_attr_ranges.clear();
+            self.capture_state.parser_replacements.clear();
+            self.capture_state.inner_attr_parser_ranges.clear();
         }
         Ok(ret)
     }
@@ -469,8 +486,9 @@ fn needs_tokens(attrs: &[ast::Attribute]) -> bool {
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(AttrWrapper, 16);
     static_assert_size!(LazyAttrTokenStreamImpl, 96);
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 1a0d9aa6378..47ca85ba060 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1,25 +1,6 @@
-use super::pat::Expected;
-use super::{
-    BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
-};
-use crate::errors::{
-    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
-    BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
-    ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
-    ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
-    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
-    GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
-    HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
-    IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
-    QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
-    StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
-    SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
-    UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
-    UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
-};
-use crate::fluent_generated as fluent;
-use crate::parser;
-use crate::parser::attr::InnerAttrPolicy;
+use std::mem::take;
+use std::ops::{Deref, DerefMut};
+
 use ast::token::IdentIsRaw;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
@@ -41,11 +22,31 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, SpanSnippetError, Symbol, DUMMY_SP};
-use std::mem::take;
-use std::ops::{Deref, DerefMut};
 use thin_vec::{thin_vec, ThinVec};
 use tracing::{debug, trace};
 
+use super::pat::Expected;
+use super::{
+    BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
+};
+use crate::errors::{
+    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
+    BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
+    ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
+    ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
+    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+    GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
+    HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
+    IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
+    QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+    StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
+    SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
+    UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+    UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
+};
+use crate::parser::attr::InnerAttrPolicy;
+use crate::{fluent_generated as fluent, parser};
+
 /// Creates a placeholder argument.
 pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
     let pat = P(Pat {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 389a6d11e19..cf5d65708ab 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,30 +1,22 @@
 // ignore-tidy-filelength
 
-use super::diagnostics::SnapshotParser;
-use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
-use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{
-    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
-    SemiColonMode, SeqSep, TokenType, Trailing,
-};
+use core::mem;
+use core::ops::ControlFlow;
 
-use crate::errors;
-use crate::maybe_recover_from_interpolated_ty_qpath;
 use ast::mut_visit::{self, MutVisitor};
 use ast::token::IdentIsRaw;
 use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
-use core::mem;
-use core::ops::ControlFlow;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::util::case::Case;
 use rustc_ast::util::classify;
 use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
 use rustc_ast::visit::{walk_expr, Visitor};
-use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID};
-use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
-use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
-use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind};
+use rustc_ast::{
+    self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
+    ClosureBinder, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, MetaItemLit,
+    Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, DUMMY_NODE_ID,
+};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
@@ -39,13 +31,14 @@ use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span};
 use thin_vec::{thin_vec, ThinVec};
 use tracing::instrument;
 
-#[derive(Debug)]
-pub(super) enum LhsExpr {
-    // Already parsed just the outer attributes.
-    Unparsed { attrs: AttrWrapper },
-    // Already parsed the expression.
-    Parsed { expr: P<Expr>, starts_statement: bool },
-}
+use super::diagnostics::SnapshotParser;
+use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
+use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
+use super::{
+    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
+    SemiColonMode, SeqSep, TokenType, Trailing,
+};
+use crate::{errors, maybe_recover_from_interpolated_ty_qpath};
 
 #[derive(Debug)]
 enum DestructuredFloat {
@@ -112,30 +105,31 @@ impl<'a> Parser<'a> {
         r: Restrictions,
         attrs: AttrWrapper,
     ) -> PResult<'a, P<Expr>> {
-        self.with_res(r, |this| this.parse_expr_assoc_with(0, LhsExpr::Unparsed { attrs }))
+        self.with_res(r, |this| this.parse_expr_assoc_with(0, attrs))
     }
 
     /// Parses an associative expression with operators of at least `min_prec` precedence.
     pub(super) fn parse_expr_assoc_with(
         &mut self,
         min_prec: usize,
-        lhs: LhsExpr,
+        attrs: AttrWrapper,
     ) -> PResult<'a, P<Expr>> {
-        let mut starts_stmt = false;
-        let mut lhs = match lhs {
-            LhsExpr::Parsed { expr, starts_statement } => {
-                starts_stmt = starts_statement;
-                expr
-            }
-            LhsExpr::Unparsed { attrs } => {
-                if self.token.is_range_separator() {
-                    return self.parse_expr_prefix_range(attrs);
-                } else {
-                    self.parse_expr_prefix(attrs)?
-                }
-            }
+        let lhs = if self.token.is_range_separator() {
+            return self.parse_expr_prefix_range(attrs);
+        } else {
+            self.parse_expr_prefix(attrs)?
         };
+        self.parse_expr_assoc_rest_with(min_prec, false, lhs)
+    }
 
+    /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
+    /// of at least `min_prec` precedence.
+    pub(super) fn parse_expr_assoc_rest_with(
+        &mut self,
+        min_prec: usize,
+        starts_stmt: bool,
+        mut lhs: P<Expr>,
+    ) -> PResult<'a, P<Expr>> {
         if !self.should_continue_as_assoc_expr(&lhs) {
             return Ok(lhs);
         }
@@ -271,7 +265,7 @@ impl<'a> Parser<'a> {
             };
             let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
                 let attrs = this.parse_outer_attributes()?;
-                this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::Unparsed { attrs })
+                this.parse_expr_assoc_with(prec + prec_adjustment, attrs)
             })?;
 
             let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
@@ -446,7 +440,7 @@ impl<'a> Parser<'a> {
             let maybe_lt = self.token.clone();
             let attrs = self.parse_outer_attributes()?;
             Some(
-                self.parse_expr_assoc_with(prec + 1, LhsExpr::Unparsed { attrs })
+                self.parse_expr_assoc_with(prec + 1, attrs)
                     .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
             )
         } else {
@@ -503,12 +497,9 @@ impl<'a> Parser<'a> {
             let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
                 // RHS must be parsed with more associativity than the dots.
                 let attrs = this.parse_outer_attributes()?;
-                this.parse_expr_assoc_with(
-                    op.unwrap().precedence() + 1,
-                    LhsExpr::Unparsed { attrs },
-                )
-                .map(|x| (lo.to(x.span), Some(x)))
-                .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
+                this.parse_expr_assoc_with(op.unwrap().precedence() + 1, attrs)
+                    .map(|x| (lo.to(x.span), Some(x)))
+                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
             } else {
                 (lo, None)
             };
@@ -617,10 +608,12 @@ impl<'a> Parser<'a> {
     /// Parse `box expr` - this syntax has been removed, but we still parse this
     /// for now to provide a more useful error
     fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> {
-        let (span, _) = self.parse_expr_prefix_common(box_kw)?;
-        let inner_span = span.with_lo(box_kw.hi());
-        let code = self.psess.source_map().span_to_snippet(inner_span).unwrap();
-        let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() });
+        let (span, expr) = self.parse_expr_prefix_common(box_kw)?;
+        // Make a multipart suggestion instead of `span_to_snippet` in case source isn't available
+        let box_kw_and_lo = box_kw.until(self.interpolated_or_expr_span(&expr));
+        let hi = span.shrink_to_hi();
+        let sugg = errors::AddBoxNew { box_kw_and_lo, hi };
+        let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span, sugg });
         Ok((span, ExprKind::Err(guar)))
     }
 
@@ -701,12 +694,12 @@ impl<'a> Parser<'a> {
                         // `foo: `
                         ExprKind::Path(None, ast::Path { segments, .. }),
                         token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
-                    ) if segments.len() == 1 => {
+                    ) if let [segment] = segments.as_slice() => {
                         let snapshot = self.create_snapshot_for_diagnostic();
                         let label = Label {
                             ident: Ident::from_str_and_span(
-                                &format!("'{}", segments[0].ident),
-                                segments[0].ident.span,
+                                &format!("'{}", segment.ident),
+                                segment.ident.span,
                             ),
                         };
                         match self.parse_expr_labeled(label, false) {
@@ -886,7 +879,7 @@ impl<'a> Parser<'a> {
         mut e: P<Expr>,
         lo: Span,
     ) -> PResult<'a, P<Expr>> {
-        let res = ensure_sufficient_stack(|| {
+        let mut res = ensure_sufficient_stack(|| {
             loop {
                 let has_question =
                     if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
@@ -933,17 +926,13 @@ impl<'a> Parser<'a> {
 
         // Stitch the list of outer attributes onto the return value. A little
         // bit ugly, but the best way given the current code structure.
-        if attrs.is_empty() {
-            res
-        } else {
-            res.map(|expr| {
-                expr.map(|mut expr| {
-                    attrs.extend(expr.attrs);
-                    expr.attrs = attrs;
-                    expr
-                })
-            })
+        if !attrs.is_empty()
+            && let Ok(expr) = &mut res
+        {
+            mem::swap(&mut expr.attrs, &mut attrs);
+            expr.attrs.extend(attrs)
         }
+        res
     }
 
     pub(super) fn parse_dot_suffix_expr(
@@ -2644,10 +2633,7 @@ impl<'a> Parser<'a> {
             self.expect(&token::Eq)?;
         }
         let attrs = self.parse_outer_attributes()?;
-        let expr = self.parse_expr_assoc_with(
-            1 + prec_let_scrutinee_needs_par(),
-            LhsExpr::Unparsed { attrs },
-        )?;
+        let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), attrs)?;
         let span = lo.to(expr.span);
         Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
     }
@@ -3152,7 +3138,8 @@ impl<'a> Parser<'a> {
 
                 if !require_comma {
                     arm_body = Some(expr);
-                    this.eat(&token::Comma);
+                    // Eat a comma if it exists, though.
+                    let _ = this.eat(&token::Comma);
                     Ok(Recovered::No)
                 } else if let Some((span, guar)) =
                     this.parse_arm_body_missing_braces(&expr, arrow_span)
@@ -3653,7 +3640,7 @@ impl<'a> Parser<'a> {
                         fields.push(f);
                     }
                     self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
-                    self.eat(&token::Comma);
+                    let _ = self.eat(&token::Comma);
                 }
             }
         }
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 523538e9643..9124c15707d 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,21 +1,19 @@
-use crate::errors::{
-    self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
-    UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
-    WhereClauseBeforeTupleStructBodySugg,
-};
-
-use super::{ForceCollect, Parser};
-
 use ast::token::Delimiter;
-use rustc_ast::token;
 use rustc_ast::{
-    self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause,
+    self as ast, token, AttrVec, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause,
 };
 use rustc_errors::{Applicability, PResult};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 use thin_vec::ThinVec;
 
+use super::{ForceCollect, Parser};
+use crate::errors::{
+    self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
+    UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
+    WhereClauseBeforeTupleStructBodySugg,
+};
+
 enum PredicateOrStructBody {
     Predicate(ast::WherePredicate),
     StructBody(ThinVec<ast::FieldDef>),
@@ -180,7 +178,8 @@ impl<'a> Parser<'a> {
                             span: this.prev_token.span,
                         });
 
-                        this.eat(&token::Comma);
+                        // Eat a trailing comma, if it exists.
+                        let _ = this.eat(&token::Comma);
                     }
 
                     let param = if this.check_lifetime() {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 112855e6d1f..8775d792c3d 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,9 +1,6 @@
-use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
-use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing};
-use crate::errors::{self, MacroExpandsToAdtField};
-use crate::fluent_generated as fluent;
-use crate::maybe_whole;
+use std::fmt::Write;
+use std::mem;
+
 use ast::token::IdentIsRaw;
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
@@ -12,18 +9,21 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::util::case::Case;
 use rustc_ast::{self as ast};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, PResult, StashKey};
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, Applicability, PResult, StashKey};
 use rustc_span::edit_distance::edit_distance;
 use rustc_span::edition::Edition;
-use rustc_span::source_map;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::ErrorGuaranteed;
-use rustc_span::{Span, DUMMY_SP};
-use std::fmt::Write;
-use std::mem;
+use rustc_span::{source_map, ErrorGuaranteed, Span, DUMMY_SP};
 use thin_vec::{thin_vec, ThinVec};
 use tracing::debug;
 
+use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
+use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
+use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing};
+use crate::errors::{self, MacroExpandsToAdtField};
+use crate::{fluent_generated as fluent, maybe_whole};
+
 impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
@@ -471,9 +471,8 @@ impl<'a> Parser<'a> {
             Err(mut err) => {
                 // Maybe the user misspelled `macro_rules` (issue #91227)
                 if self.token.is_ident()
-                    && path.segments.len() == 1
-                    && edit_distance("macro_rules", &path.segments[0].ident.to_string(), 2)
-                        .is_some()
+                    && let [segment] = path.segments.as_slice()
+                    && edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some()
                 {
                     err.span_suggestion(
                         path.span,
@@ -1192,13 +1191,14 @@ impl<'a> Parser<'a> {
         mut safety: Safety,
     ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
+        // FIXME: This recovery should be tested better.
         if safety == Safety::Default
             && self.token.is_keyword(kw::Unsafe)
             && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
         {
             self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
             safety = Safety::Unsafe(self.token.span);
-            self.eat_keyword(kw::Unsafe);
+            let _ = self.eat_keyword(kw::Unsafe);
         }
         let module = ast::ForeignMod {
             safety,
@@ -1759,7 +1759,7 @@ impl<'a> Parser<'a> {
                     }
                 }
             }
-            self.eat(&token::CloseDelim(Delimiter::Brace));
+            self.expect(&token::CloseDelim(Delimiter::Brace))?;
         } else {
             let token_str = super::token_descr(&self.token);
             let where_str = if parsed_where { "" } else { "`where`, or " };
@@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> {
                         if let Some(_guar) = guar {
                             // Handle a case like `Vec<u8>>,` where we can continue parsing fields
                             // after the comma
-                            self.eat(&token::Comma);
+                            let _ = self.eat(&token::Comma);
 
                             // `check_trailing_angle_brackets` already emitted a nicer error, as
                             // proven by the presence of `_guar`. We can continue parsing.
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e7240869a39..9b3b6d5f9ad 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -10,18 +10,21 @@ mod path;
 mod stmt;
 mod ty;
 
-use crate::lexer::UnmatchedDelim;
+use std::assert_matches::debug_assert_matches;
+use std::ops::Range;
+use std::{fmt, mem, slice};
+
 use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 pub(crate) use expr::ForbiddenLetReason;
 pub(crate) use item::FnParseMode;
 pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 use path::PathStyle;
-
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrsTarget, DelimSpacing, DelimSpan, Spacing};
-use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
+use rustc_ast::tokenstream::{
+    AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor,
+};
 use rustc_ast::util::case::Case;
 use rustc_ast::{
     self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
@@ -35,14 +38,13 @@ use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use std::ops::Range;
-use std::{fmt, mem, slice};
 use thin_vec::ThinVec;
 use tracing::debug;
 
 use crate::errors::{
     self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
 };
+use crate::lexer::UnmatchedDelim;
 
 #[cfg(test)]
 mod tests;
@@ -191,24 +193,54 @@ struct ClosureSpans {
     body: Span,
 }
 
-/// Indicates a range of tokens that should be replaced by
-/// the tokens in the provided `AttrsTarget`. This is used in two
-/// places during token collection:
+/// A token range within a `Parser`'s full token stream.
+#[derive(Clone, Debug)]
+struct ParserRange(Range<u32>);
+
+/// A token range within an individual AST node's (lazy) token stream, i.e.
+/// relative to that node's first token. Distinct from `ParserRange` so the two
+/// kinds of range can't be mixed up.
+#[derive(Clone, Debug)]
+struct NodeRange(Range<u32>);
+
+/// Indicates a range of tokens that should be replaced by an `AttrsTarget`
+/// (replacement) or be replaced by nothing (deletion). This is used in two
+/// places during token collection.
 ///
-/// 1. During the parsing of an AST node that may have a `#[derive]`
-/// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
-/// In this case, we use a `ReplaceRange` to replace the entire inner AST node
-/// with `FlatToken::AttrsTarget`, allowing us to perform eager cfg-expansion
-/// on an `AttrTokenStream`.
+/// 1. Replacement. During the parsing of an AST node that may have a
+///    `#[derive]` attribute, when we parse a nested AST node that has `#[cfg]`
+///    or `#[cfg_attr]`, we replace the entire inner AST node with
+///    `FlatToken::AttrsTarget`. This lets us perform eager cfg-expansion on an
+///    `AttrTokenStream`.
 ///
-/// 2. When we parse an inner attribute while collecting tokens. We
-/// remove inner attributes from the token stream entirely, and
-/// instead track them through the `attrs` field on the AST node.
-/// This allows us to easily manipulate them (for example, removing
-/// the first macro inner attribute to invoke a proc-macro).
-/// When create a `TokenStream`, the inner attributes get inserted
-/// into the proper place in the token stream.
-type ReplaceRange = (Range<u32>, Option<AttrsTarget>);
+/// 2. Deletion. We delete inner attributes from all collected token streams,
+///    and instead track them through the `attrs` field on the AST node. This
+///    lets us manipulate them similarly to outer attributes. When we create a
+///    `TokenStream`, the inner attributes are inserted into the proper place
+///    in the token stream.
+///
+/// Each replacement starts off in `ParserReplacement` form but is converted to
+/// `NodeReplacement` form when it is attached to a single AST node, via
+/// `LazyAttrTokenStreamImpl`.
+type ParserReplacement = (ParserRange, Option<AttrsTarget>);
+
+/// See the comment on `ParserReplacement`.
+type NodeReplacement = (NodeRange, Option<AttrsTarget>);
+
+impl NodeRange {
+    // Converts a range within a parser's tokens to a range within a
+    // node's tokens beginning at `start_pos`.
+    //
+    // For example, imagine a parser with 50 tokens in its token stream, a
+    // function that spans `ParserRange(20..40)` and an inner attribute within
+    // that function that spans `ParserRange(30..35)`. We would find the inner
+    // attribute's range within the function's tokens by subtracting 20, which
+    // is the position of the function's start token. This gives
+    // `NodeRange(10..15)`.
+    fn new(ParserRange(parser_range): ParserRange, start_pos: u32) -> NodeRange {
+        NodeRange((parser_range.start - start_pos)..(parser_range.end - start_pos))
+    }
+}
 
 /// Controls how we capture tokens. Capturing can be expensive,
 /// so we try to avoid performing capturing in cases where
@@ -225,8 +257,8 @@ enum Capturing {
 #[derive(Clone, Debug)]
 struct CaptureState {
     capturing: Capturing,
-    replace_ranges: Vec<ReplaceRange>,
-    inner_attr_ranges: FxHashMap<AttrId, Range<u32>>,
+    parser_replacements: Vec<ParserReplacement>,
+    inner_attr_parser_ranges: FxHashMap<AttrId, ParserRange>,
 }
 
 /// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that
@@ -416,8 +448,8 @@ impl<'a> Parser<'a> {
             subparser_name,
             capture_state: CaptureState {
                 capturing: Capturing::No,
-                replace_ranges: Vec::new(),
-                inner_attr_ranges: Default::default(),
+                parser_replacements: Vec::new(),
+                inner_attr_parser_ranges: Default::default(),
             },
             current_closure: None,
             recovery: Recovery::Allowed,
@@ -546,6 +578,7 @@ impl<'a> Parser<'a> {
     }
 
     #[inline]
+    #[must_use]
     fn check_noexpect(&self, tok: &TokenKind) -> bool {
         self.token == *tok
     }
@@ -555,6 +588,7 @@ impl<'a> Parser<'a> {
     /// the main purpose of this function is to reduce the cluttering of the suggestions list
     /// which using the normal eat method could introduce in some cases.
     #[inline]
+    #[must_use]
     fn eat_noexpect(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.check_noexpect(tok);
         if is_present {
@@ -565,6 +599,7 @@ impl<'a> Parser<'a> {
 
     /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
     #[inline]
+    #[must_use]
     pub fn eat(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.check(tok);
         if is_present {
@@ -576,12 +611,14 @@ impl<'a> Parser<'a> {
     /// If the next token is the given keyword, returns `true` without eating it.
     /// An expectation is also added for diagnostics purposes.
     #[inline]
+    #[must_use]
     fn check_keyword(&mut self, kw: Symbol) -> bool {
         self.expected_tokens.push(TokenType::Keyword(kw));
         self.token.is_keyword(kw)
     }
 
     #[inline]
+    #[must_use]
     fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
         if self.check_keyword(kw) {
             return true;
@@ -601,6 +638,7 @@ impl<'a> Parser<'a> {
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
     // Public for rustc_builtin_macros and rustfmt usage.
     #[inline]
+    #[must_use]
     pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
         if self.check_keyword(kw) {
             self.bump();
@@ -614,6 +652,7 @@ impl<'a> Parser<'a> {
     /// If the case differs (and is ignored) an error is issued.
     /// This is useful for recovery.
     #[inline]
+    #[must_use]
     fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
         if self.eat_keyword(kw) {
             return true;
@@ -635,6 +674,7 @@ impl<'a> Parser<'a> {
     /// Otherwise, returns `false`. No expectation is added.
     // Public for rustc_builtin_macros usage.
     #[inline]
+    #[must_use]
     pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
         if self.token.is_keyword(kw) {
             self.bump();
@@ -647,7 +687,7 @@ impl<'a> Parser<'a> {
     /// If the given word is not a keyword, signals an error.
     /// If the next token is not the given word, signals an error.
     /// Otherwise, eats it.
-    fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> {
+    pub fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> {
         if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) }
     }
 
@@ -1024,8 +1064,11 @@ impl<'a> Parser<'a> {
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
-        if matches!(recovered, Recovered::No) {
-            self.eat(ket);
+        if matches!(recovered, Recovered::No) && !self.eat(ket) {
+            self.dcx().span_delayed_bug(
+                self.token.span,
+                "recovered but `parse_seq_to_before_end` did not give us the ket token",
+            );
         }
         Ok((val, trailing))
     }
@@ -1124,10 +1167,12 @@ impl<'a> Parser<'a> {
             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))
+                    match tree {
+                        TokenTree::Token(token, _) => return looker(token),
+                        &TokenTree::Delimited(dspan, _, delim, _) => {
+                            if delim != Delimiter::Invisible {
+                                return looker(&Token::new(token::OpenDelim(delim), dspan.open));
+                            }
                         }
                     };
                 }
@@ -1208,9 +1253,6 @@ impl<'a> Parser<'a> {
         if self.eat_keyword_case(kw::Unsafe, case) {
             Safety::Unsafe(self.prev_token.uninterpolated_span())
         } else if self.eat_keyword_case(kw::Safe, case) {
-            self.psess
-                .gated_spans
-                .gate(sym::unsafe_extern_blocks, self.prev_token.uninterpolated_span());
             Safety::Safe(self.prev_token.uninterpolated_span())
         } else {
             Safety::Default
@@ -1249,7 +1291,7 @@ impl<'a> Parser<'a> {
         if pat {
             self.psess.gated_spans.gate(sym::inline_const_pat, span);
         }
-        self.eat_keyword(kw::Const);
+        self.expect_keyword(kw::Const)?;
         let (attrs, blk) = self.parse_inner_attrs_and_block()?;
         let anon_const = AnonConst {
             id: DUMMY_NODE_ID,
@@ -1346,7 +1388,7 @@ impl<'a> Parser<'a> {
                     // can capture these tokens if necessary.
                     self.bump();
                     if self.token_cursor.stack.len() == target_depth {
-                        debug_assert!(matches!(self.token.kind, token::CloseDelim(_)));
+                        debug_assert_matches!(self.token.kind, token::CloseDelim(_));
                         break;
                     }
                 }
diff --git a/compiler/rustc_parse/src/parser/mut_visit/tests.rs b/compiler/rustc_parse/src/parser/mut_visit/tests.rs
index 677bcdf7fcd..b82c295732d 100644
--- a/compiler/rustc_parse/src/parser/mut_visit/tests.rs
+++ b/compiler/rustc_parse/src/parser/mut_visit/tests.rs
@@ -1,10 +1,11 @@
-use crate::parser::tests::{matches_codepattern, string_to_crate};
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast_pretty::pprust;
 use rustc_span::create_default_session_globals_then;
 use rustc_span::symbol::Ident;
 
+use crate::parser::tests::{matches_codepattern, string_to_crate};
+
 // This version doesn't care about getting comments or doc-strings in.
 fn print_crate_items(krate: &ast::Crate) -> String {
     krate.items.iter().map(|i| pprust::item_to_string(i)).collect::<Vec<_>>().join(" ")
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 886d6af1735..999f6f0eeb0 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,7 +1,8 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{
-    self, Delimiter, Nonterminal::*, NonterminalKind, NtExprKind::*, NtPatKind::*, Token,
-};
+use rustc_ast::token::Nonterminal::*;
+use rustc_ast::token::NtExprKind::*;
+use rustc_ast::token::NtPatKind::*;
+use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
 use rustc_ast::HasTokens;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
@@ -38,6 +39,7 @@ impl<'a> Parser<'a> {
         }
 
         match kind {
+            // `expr_2021` and earlier
             NonterminalKind::Expr(Expr2021 { .. }) => {
                 token.can_begin_expr()
                 // This exception is here for backwards compatibility.
@@ -45,8 +47,16 @@ impl<'a> Parser<'a> {
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Const)
             }
+            // Current edition expressions
             NonterminalKind::Expr(Expr) => {
-                token.can_begin_expr()
+                // In Edition 2024, `_` is considered an expression, so we
+                // need to allow it here because `token.can_begin_expr()` does
+                // not consider `_` to be an expression.
+                //
+                // Because `can_begin_expr` is used elsewhere, we need to reduce
+                // the scope of where the `_` is considered an expression to
+                // just macro parsing code.
+                (token.can_begin_expr() || token.is_keyword(kw::Underscore))
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Let)
             }
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index aa818878cd8..5bfb8bdf776 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,17 +1,3 @@
-use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing};
-use crate::errors::{
-    self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
-    DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
-    ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
-    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
-    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};
 use rustc_ast::mut_visit::{walk_pat, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
@@ -27,6 +13,21 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, ErrorGuaranteed, Span};
 use thin_vec::{thin_vec, ThinVec};
 
+use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing};
+use crate::errors::{
+    self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
+    DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
+    ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
+    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
+    ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
+    SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
+    TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
+    UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
+    UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
+};
+use crate::parser::expr::could_be_unclosed_char_literal;
+use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum Expected {
     ParameterName,
@@ -402,8 +403,9 @@ impl<'a> Parser<'a> {
 
             // Parse an associative expression such as `+ expr`, `% expr`, ...
             // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
-            let lhs = LhsExpr::Parsed { expr, starts_statement: false };
-            if let Ok(expr) = snapshot.parse_expr_assoc_with(0, lhs).map_err(|err| err.cancel()) {
+            if let Ok(expr) =
+                snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel())
+            {
                 // We got a valid expression.
                 self.restore_snapshot(snapshot);
                 self.restrictions.remove(Restrictions::IS_PAT);
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index b9014dea726..6f82d6b9826 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -1,8 +1,5 @@
-use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{Parser, Restrictions, TokenType};
-use crate::errors::PathSingleColon;
-use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
-use crate::{errors, maybe_whole};
+use std::mem;
+
 use ast::token::IdentIsRaw;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@@ -14,10 +11,15 @@ use rustc_ast::{
 use rustc_errors::{Applicability, Diag, PResult};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span};
-use std::mem;
 use thin_vec::ThinVec;
 use tracing::debug;
 
+use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
+use super::{Parser, Restrictions, TokenType};
+use crate::errors::PathSingleColon;
+use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
+use crate::{errors, maybe_whole};
+
 /// Specifies how to parse a path.
 #[derive(Copy, Clone, PartialEq)]
 pub(super) enum PathStyle {
@@ -311,7 +313,8 @@ impl<'a> Parser<'a> {
                 }
 
                 // Generic arguments are found - `<`, `(`, `::<` or `::(`.
-                self.eat(&token::PathSep);
+                // First, eat `::` if it exists.
+                let _ = self.eat(&token::PathSep);
                 let lo = self.token.span;
                 let args = if self.eat_lt() {
                     // `<'a, T, A = U>`
@@ -823,7 +826,8 @@ impl<'a> Parser<'a> {
             // We can only resolve single-segment paths at the moment, because multi-segment paths
             // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
             ast::ExprKind::Path(None, path)
-                if path.segments.len() == 1 && path.segments[0].args.is_none() =>
+                if let [segment] = path.segments.as_slice()
+                    && segment.args.is_none() =>
             {
                 true
             }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index d8de7c1bfa1..b206f134f0e 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -1,31 +1,30 @@
-use super::attr::InnerAttrForbiddenReason;
-use super::diagnostics::AttemptLocalParseRecovery;
-use super::expr::LhsExpr;
-use super::pat::{PatternLocation, RecoverComma};
-use super::path::PathStyle;
-use super::{
-    AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
-};
-use crate::errors;
-use crate::maybe_whole;
+use std::borrow::Cow;
+use std::mem;
 
-use crate::errors::MalformedLoopLabel;
 use ast::Label;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::util::classify::{self, TrailingBrace};
-use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
-use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Recovered, Stmt};
-use rustc_ast::{StmtKind, DUMMY_NODE_ID};
+use rustc_ast::{
+    AttrStyle, AttrVec, Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, LocalKind, MacCall,
+    MacCallStmt, MacStmtStyle, Recovered, Stmt, StmtKind, DUMMY_NODE_ID,
+};
 use rustc_errors::{Applicability, Diag, PResult};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, ErrorGuaranteed, Span};
-
-use std::borrow::Cow;
-use std::mem;
 use thin_vec::{thin_vec, ThinVec};
 
+use super::attr::InnerAttrForbiddenReason;
+use super::diagnostics::AttemptLocalParseRecovery;
+use super::pat::{PatternLocation, RecoverComma};
+use super::path::PathStyle;
+use super::{
+    AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
+};
+use crate::errors::MalformedLoopLabel;
+use crate::{errors, maybe_whole};
+
 impl<'a> Parser<'a> {
     /// Parses a statement. This stops just before trailing semicolons on everything but items.
     /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
@@ -66,7 +65,12 @@ impl<'a> Parser<'a> {
         }
 
         Ok(Some(if self.token.is_keyword(kw::Let) {
-            self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
+            self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+                this.expect_keyword(kw::Let)?;
+                let local = this.parse_local(attrs)?;
+                let trailing = capture_semi && this.token.kind == token::Semi;
+                Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
+            })?
         } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
             self.recover_stmt_local_after_let(
                 lo,
@@ -112,13 +116,12 @@ impl<'a> Parser<'a> {
                 }
             }
         } else if let Some(item) = self.parse_item_common(
-            attrs.clone(),
+            attrs.clone(), // FIXME: unwanted clone of attrs
             false,
             true,
             FnParseMode { req_name: |_| true, req_body: true },
             force_collect,
         )? {
-            // FIXME: Bad copy of attrs
             self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
         } else if self.eat(&token::Semi) {
             // Do not attempt to parse an expression if we're done here.
@@ -173,7 +176,7 @@ impl<'a> Parser<'a> {
             // Perform this outside of the `collect_tokens_trailing_token` closure,
             // since our outer attributes do not apply to this part of the expression
             let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
-                this.parse_expr_assoc_with(0, LhsExpr::Parsed { expr, starts_statement: true })
+                this.parse_expr_assoc_rest_with(0, true, expr)
             })?;
             Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
         } else {
@@ -206,8 +209,7 @@ impl<'a> Parser<'a> {
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
             let e = self.maybe_recover_from_bad_qpath(e)?;
             let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
-            let e = self
-                .parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?;
+            let e = self.parse_expr_assoc_rest_with(0, false, e)?;
             StmtKind::Expr(e)
         };
         Ok(self.mk_stmt(lo.to(hi), kind))
@@ -247,21 +249,6 @@ impl<'a> Parser<'a> {
         Ok(stmt)
     }
 
-    fn parse_local_mk(
-        &mut self,
-        lo: Span,
-        attrs: AttrWrapper,
-        capture_semi: bool,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Stmt> {
-        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
-            this.expect_keyword(kw::Let)?;
-            let local = this.parse_local(attrs)?;
-            let trailing = capture_semi && this.token.kind == token::Semi;
-            Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
-        })
-    }
-
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
@@ -421,10 +408,14 @@ impl<'a> Parser<'a> {
     fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> {
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
-                // Recover `let x <op>= 1` as `let x = 1`
+                // Recover `let x <op>= 1` as `let x = 1` We must not use `+ BytePos(1)` here
+                // because `<op>` can be a multi-byte lookalike that was recovered, e.g. `➖=` (the
+                // `➖` is a U+2796 Heavy Minus Sign Unicode Character) that was recovered as a
+                // `-=`.
+                let extra_op_span = self.psess.source_map().start_point(self.token.span);
                 self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet {
                     span: self.token.span,
-                    suggestion: self.token.span.with_hi(self.token.span.lo() + BytePos(1)),
+                    suggestion: extra_op_span,
                 });
                 self.bump();
                 true
@@ -685,7 +676,7 @@ impl<'a> Parser<'a> {
 
                             match &expr.kind {
                                 ExprKind::Path(None, ast::Path { segments, .. })
-                                    if segments.len() == 1 =>
+                                    if let [segment] = segments.as_slice() =>
                                 {
                                     if self.token == token::Colon
                                         && self.look_ahead(1, |token| {
@@ -702,8 +693,8 @@ impl<'a> Parser<'a> {
                                         let snapshot = self.create_snapshot_for_diagnostic();
                                         let label = Label {
                                             ident: Ident::from_str_and_span(
-                                                &format!("'{}", segments[0].ident),
-                                                segments[0].ident.span,
+                                                &format!("'{}", segment.ident),
+                                                segment.ident.span,
                                             ),
                                         };
                                         match self.parse_expr_labeled(label, false) {
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index 491aa71155a..cb8e8d30988 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -1,30 +1,28 @@
-use crate::parser::ForceCollect;
-use crate::{
-    new_parser_from_source_str, parser::Parser, source_str_to_stream, unwrap_or_emit_fatal,
-};
+use std::assert_matches::assert_matches;
+use std::io::prelude::*;
+use std::iter::Peekable;
+use std::path::{Path, PathBuf};
+use std::sync::{Arc, Mutex};
+use std::{io, str};
+
 use ast::token::IdentIsRaw;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
-use rustc_ast::visit;
-use rustc_ast::{self as ast, PatKind};
+use rustc_ast::{self as ast, visit, PatKind};
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::HumanEmitter;
 use rustc_errors::{DiagCtxt, MultiSpan, PResult};
 use rustc_session::parse::ParseSess;
-use rustc_span::create_default_session_globals_then;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{BytePos, FileName, Pos, Span};
-use std::io;
-use std::io::prelude::*;
-use std::iter::Peekable;
-use std::path::{Path, PathBuf};
-use std::str;
-use std::sync::{Arc, Mutex};
+use rustc_span::{create_default_session_globals_then, BytePos, FileName, Pos, Span};
 use termcolor::WriteColor;
 
+use crate::parser::{ForceCollect, Parser};
+use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
+
 fn psess() -> ParseSess {
     ParseSess::new(vec![crate::DEFAULT_LOCALE_RESOURCE, crate::DEFAULT_LOCALE_RESOURCE])
 }
@@ -1750,7 +1748,7 @@ fn out_of_line_mod() {
         .unwrap();
 
         let ast::ItemKind::Mod(_, mod_kind) = &item.kind else { panic!() };
-        assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
+        assert_matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2);
     });
 }
 
diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs
index 9be00a14791..d518dfee2b2 100644
--- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs
+++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs
@@ -1,8 +1,8 @@
-use crate::parser::tests::string_to_stream;
 use rustc_ast::token::{self, IdentIsRaw};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_span::create_default_session_globals_then;
-use rustc_span::{BytePos, Span, Symbol};
+use rustc_span::{create_default_session_globals_then, BytePos, Span, Symbol};
+
+use crate::parser::tests::string_to_stream;
 
 fn string_to_ts(string: &str) -> TokenStream {
     string_to_stream(string.to_owned())
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index f95ecd254ce..352ddd9eac4 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,13 +1,3 @@
-use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
-
-use crate::errors::{
-    self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
-    FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
-    HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
-    NestedCVariadicType, ReturnTypesUseThinArrow,
-};
-use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
-
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind};
 use rustc_ast::util::case::Case;
@@ -21,6 +11,15 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 use thin_vec::{thin_vec, ThinVec};
 
+use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
+use crate::errors::{
+    self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
+    FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
+    HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
+    NestedCVariadicType, ReturnTypesUseThinArrow,
+};
+use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+
 /// Signals whether parsing a type should allow `+`.
 ///
 /// For example, let T be the type `impl Default + 'static`
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 3d5e6371f4c..a64c00f3b6c 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -1,7 +1,5 @@
 //! Meta-syntax validation logic of attributes for post-expansion.
 
-use crate::{errors, parse_in};
-
 use rustc_ast::token::Delimiter;
 use rustc_ast::tokenstream::DelimSpan;
 use rustc_ast::{
@@ -18,6 +16,8 @@ use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, BytePos, Span, Symbol};
 
+use crate::{errors, parse_in};
+
 pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
     if attr.is_doc_comment() {
         return;
@@ -26,76 +26,35 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
     let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
     let attr_item = attr.get_normal_item();
 
-    let is_unsafe_attr = attr_info.is_some_and(|attr| attr.safety == AttributeSafety::Unsafe);
-
-    if features.unsafe_attributes {
-        if is_unsafe_attr {
-            if let ast::Safety::Default = attr_item.unsafety {
-                let path_span = attr_item.path.span;
-
-                // If the `attr_item`'s span is not from a macro, then just suggest
-                // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
-                // `unsafe(`, `)` right after and right before the opening and closing
-                // square bracket respectively.
-                let diag_span = if attr_item.span().can_be_used_for_suggestions() {
-                    attr_item.span()
-                } else {
-                    attr.span
-                        .with_lo(attr.span.lo() + BytePos(2))
-                        .with_hi(attr.span.hi() - BytePos(1))
-                };
-
-                if attr.span.at_least_rust_2024() {
-                    psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
-                        span: path_span,
-                        suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {
-                            left: diag_span.shrink_to_lo(),
-                            right: diag_span.shrink_to_hi(),
-                        },
-                    });
-                } else {
-                    psess.buffer_lint(
-                        UNSAFE_ATTR_OUTSIDE_UNSAFE,
-                        path_span,
-                        ast::CRATE_NODE_ID,
-                        BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
-                            attribute_name_span: path_span,
-                            sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
-                        },
-                    );
-                }
-            }
-        } else {
-            if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
-                psess.dcx().emit_err(errors::InvalidAttrUnsafe {
-                    span: unsafe_span,
-                    name: attr_item.path.clone(),
-                });
-            }
-        }
-    }
+    // All non-builtin attributes are considered safe
+    let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
+    check_attribute_safety(features, psess, safety, attr);
 
     // Check input tokens for built-in and key-value attributes.
     match attr_info {
         // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
         Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
             match parse_meta(psess, attr) {
-                Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, *name, *template),
+                // Don't check safety again, we just did that
+                Ok(meta) => check_builtin_meta_item(
+                    features, psess, &meta, attr.style, *name, *template, false,
+                ),
                 Err(err) => {
                     err.emit();
                 }
             }
         }
-        _ if let AttrArgs::Eq(..) = attr_item.args => {
-            // All key-value attributes are restricted to meta-item syntax.
-            match parse_meta(psess, attr) {
-                Ok(_) => {}
-                Err(err) => {
-                    err.emit();
+        _ => {
+            if let AttrArgs::Eq(..) = attr_item.args {
+                // All key-value attributes are restricted to meta-item syntax.
+                match parse_meta(psess, attr) {
+                    Ok(_) => {}
+                    Err(err) => {
+                        err.emit();
+                    }
                 }
             }
         }
-        _ => {}
     }
 }
 
@@ -198,12 +157,85 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
     }
 }
 
+pub fn check_attribute_safety(
+    features: &Features,
+    psess: &ParseSess,
+    safety: AttributeSafety,
+    attr: &Attribute,
+) {
+    if !features.unsafe_attributes {
+        return;
+    }
+
+    let attr_item = attr.get_normal_item();
+
+    if safety == AttributeSafety::Unsafe {
+        if let ast::Safety::Default = attr_item.unsafety {
+            let path_span = attr_item.path.span;
+
+            // If the `attr_item`'s span is not from a macro, then just suggest
+            // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
+            // `unsafe(`, `)` right after and right before the opening and closing
+            // square bracket respectively.
+            let diag_span = if attr_item.span().can_be_used_for_suggestions() {
+                attr_item.span()
+            } else {
+                attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1))
+            };
+
+            if attr.span.at_least_rust_2024() {
+                psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
+                    span: path_span,
+                    suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {
+                        left: diag_span.shrink_to_lo(),
+                        right: diag_span.shrink_to_hi(),
+                    },
+                });
+            } else {
+                psess.buffer_lint(
+                    UNSAFE_ATTR_OUTSIDE_UNSAFE,
+                    path_span,
+                    ast::CRATE_NODE_ID,
+                    BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
+                        attribute_name_span: path_span,
+                        sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
+                    },
+                );
+            }
+        }
+    } else {
+        if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
+            psess.dcx().emit_err(errors::InvalidAttrUnsafe {
+                span: unsafe_span,
+                name: attr_item.path.clone(),
+            });
+        }
+    }
+}
+
+// Called by `check_builtin_meta_item` and code that manually denies
+// `unsafe(...)` in `cfg`
+pub fn deny_builtin_meta_unsafety(features: &Features, psess: &ParseSess, meta: &MetaItem) {
+    // This only supports denying unsafety right now - making builtin attributes
+    // support unsafety will requite us to thread the actual `Attribute` through
+    // for the nice diagnostics.
+    if features.unsafe_attributes {
+        if let Safety::Unsafe(unsafe_span) = meta.unsafety {
+            psess
+                .dcx()
+                .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() });
+        }
+    }
+}
+
 pub fn check_builtin_meta_item(
+    features: &Features,
     psess: &ParseSess,
     meta: &MetaItem,
     style: ast::AttrStyle,
     name: Symbol,
     template: AttributeTemplate,
+    deny_unsafety: bool,
 ) {
     // Some special attributes like `cfg` must be checked
     // before the generic check, so we skip them here.
@@ -212,6 +244,10 @@ pub fn check_builtin_meta_item(
     if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
         emit_malformed_attribute(psess, style, meta.span, name, template);
     }
+
+    if deny_unsafety {
+        deny_builtin_meta_unsafety(features, psess, meta);
+    }
 }
 
 fn emit_malformed_attribute(
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 7e22644977d..cb758150789 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -15,16 +15,14 @@
 )]
 // tidy-alphabetical-end
 
+use std::{iter, str, string};
+
 use rustc_lexer::unescape;
 pub use Alignment::*;
 pub use Count::*;
 pub use Piece::*;
 pub use Position::*;
 
-use std::iter;
-use std::str;
-use std::string;
-
 // Note: copied from rustc_span
 /// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index bfe0d54e645..0318d34fb73 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -100,6 +100,10 @@ passes_continue_labeled_block =
     .label = labeled blocks cannot be `continue`'d
     .block_label = labeled block the `continue` points to
 
+passes_coroutine_on_non_closure =
+    attribute should be applied to closures
+    .label = not a closure
+
 passes_coverage_not_fn_or_closure =
     attribute should be applied to a function definition or closure
     .label = not a function or closure
@@ -219,6 +223,9 @@ passes_doc_masked_only_extern_crate =
     .not_an_extern_crate_label = not an `extern crate` item
     .note = read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
 
+passes_doc_rust_logo =
+    the `#[doc(rust_logo)]` attribute is used for Rust branding
+
 passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
 
 passes_doc_test_takes_list =
@@ -542,6 +549,10 @@ passes_only_has_effect_on =
         *[unspecified] (unspecified--this is a compiler bug)
     }
 
+passes_optimize_not_fn_or_closure =
+    attribute should be applied to function or closure
+    .label = not a function or closure
+
 passes_outer_crate_level_attr =
     crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
 
@@ -587,6 +598,9 @@ passes_remove_fields =
      *[other] fields
     }
 
+passes_repr_align_function =
+    `repr(align)` attributes on functions are unstable
+
 passes_repr_conflicting =
     conflicting representation hints
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index e0cf65d3f98..bd157d1d619 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,28 +4,29 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::{errors, fluent_generated as fluent};
-use rustc_ast::{ast, AttrKind, AttrStyle, Attribute, LitKind};
-use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem};
+use std::cell::Cell;
+use std::collections::hash_map::Entry;
+
+use rustc_ast::{
+    ast, AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem,
+};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, IntoDiagArg, MultiSpan};
-use rustc_errors::{DiagCtxtHandle, StashKey};
+use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir};
 use rustc_hir::{
-    self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
+    self as hir, self, FnSig, ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target,
+    TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
-use rustc_hir::{MethodKind, Safety, Target};
 use rustc_macros::LintDiagnostic;
-use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
@@ -37,10 +38,10 @@ use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
 use rustc_trait_selection::traits::ObligationCtxt;
-use std::cell::Cell;
-use std::collections::hash_map::Entry;
 use tracing::debug;
 
+use crate::{errors, fluent_generated as fluent};
+
 #[derive(LintDiagnostic)]
 #[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
 struct DiagnosticOnUnimplementedOnlyForTraits;
@@ -115,132 +116,185 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
             match attr.path().as_slice() {
-                [sym::diagnostic, sym::do_not_recommend] => {
+                [sym::diagnostic, sym::do_not_recommend, ..] => {
                     self.check_do_not_recommend(attr.span, hir_id, target)
                 }
-                [sym::diagnostic, sym::on_unimplemented] => {
+                [sym::diagnostic, sym::on_unimplemented, ..] => {
                     self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
                 }
-                [sym::inline] => self.check_inline(hir_id, attr, span, target),
-                [sym::coverage] => self.check_coverage(attr, span, target),
-                [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
-                [sym::marker] => self.check_marker(hir_id, attr, span, target),
-                [sym::target_feature] => {
+                [sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
+                [sym::coverage, ..] => self.check_coverage(attr, span, target),
+                [sym::optimize, ..] => self.check_optimize(hir_id, attr, target),
+                [sym::no_sanitize, ..] => self.check_no_sanitize(hir_id, attr, span, target),
+                [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
+                [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
+                [sym::target_feature, ..] => {
                     self.check_target_feature(hir_id, attr, span, target, attrs)
                 }
-                [sym::thread_local] => self.check_thread_local(attr, span, target),
-                [sym::track_caller] => {
+                [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
+                [sym::track_caller, ..] => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
                 }
-                [sym::doc] => self.check_doc_attrs(
+                [sym::doc, ..] => self.check_doc_attrs(
                     attr,
                     hir_id,
                     target,
                     &mut specified_inline,
                     &mut doc_aliases,
                 ),
-                [sym::no_link] => self.check_no_link(hir_id, attr, span, target),
-                [sym::export_name] => self.check_export_name(hir_id, attr, span, target),
-                [sym::rustc_layout_scalar_valid_range_start]
-                | [sym::rustc_layout_scalar_valid_range_end] => {
+                [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
+                [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
+                [sym::rustc_layout_scalar_valid_range_start, ..]
+                | [sym::rustc_layout_scalar_valid_range_end, ..] => {
                     self.check_rustc_layout_scalar_valid_range(attr, span, target)
                 }
-                [sym::allow_internal_unstable] => {
+                [sym::allow_internal_unstable, ..] => {
                     self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
                 }
-                [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target),
-                [sym::rustc_allow_const_fn_unstable] => {
+                [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
+                [sym::rustc_allow_const_fn_unstable, ..] => {
                     self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
                 }
-                [sym::rustc_std_internal_symbol] => {
+                [sym::rustc_std_internal_symbol, ..] => {
                     self.check_rustc_std_internal_symbol(attr, span, target)
                 }
-                [sym::naked] => self.check_naked(hir_id, attr, span, target, attrs),
-                [sym::rustc_never_returns_null_ptr] => {
+                [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
+                [sym::rustc_never_returns_null_ptr, ..] => {
                     self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                 }
-                [sym::rustc_legacy_const_generics] => {
+                [sym::rustc_legacy_const_generics, ..] => {
                     self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
                 }
-                [sym::rustc_lint_query_instability] => {
+                [sym::rustc_lint_query_instability, ..] => {
                     self.check_rustc_lint_query_instability(hir_id, attr, span, target)
                 }
-                [sym::rustc_lint_diagnostics] => {
+                [sym::rustc_lint_diagnostics, ..] => {
                     self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
                 }
-                [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target),
-                [sym::rustc_lint_opt_deny_field_access] => {
+                [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
+                [sym::rustc_lint_opt_deny_field_access, ..] => {
                     self.check_rustc_lint_opt_deny_field_access(attr, span, target)
                 }
-                [sym::rustc_clean]
-                | [sym::rustc_dirty]
-                | [sym::rustc_if_this_changed]
-                | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr),
-                [sym::rustc_coinductive]
-                | [sym::rustc_must_implement_one_of]
-                | [sym::rustc_deny_explicit_impl]
-                | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target),
-                [sym::cmse_nonsecure_entry] => {
+                [sym::rustc_clean, ..]
+                | [sym::rustc_dirty, ..]
+                | [sym::rustc_if_this_changed, ..]
+                | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
+                [sym::rustc_coinductive, ..]
+                | [sym::rustc_must_implement_one_of, ..]
+                | [sym::rustc_deny_explicit_impl, ..]
+                | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
+                [sym::cmse_nonsecure_entry, ..] => {
                     self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
                 }
-                [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target),
-                [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target),
-                [sym::must_use] => self.check_must_use(hir_id, attr, target),
-                [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target),
-                [sym::rustc_allow_incoherent_impl] => {
+                [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
+                [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
+                [sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
+                [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
+                [sym::rustc_allow_incoherent_impl, ..] => {
                     self.check_allow_incoherent_impl(attr, span, target)
                 }
-                [sym::rustc_has_incoherent_inherent_impls] => {
+                [sym::rustc_has_incoherent_inherent_impls, ..] => {
                     self.check_has_incoherent_inherent_impls(attr, span, target)
                 }
-                [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target),
-                [sym::ffi_const] => self.check_ffi_const(attr.span, target),
-                [sym::rustc_const_unstable]
-                | [sym::rustc_const_stable]
-                | [sym::unstable]
-                | [sym::stable]
-                | [sym::rustc_allowed_through_unstable_modules]
-                | [sym::rustc_promotable] => self.check_stability_promotable(attr, target),
-                [sym::link_ordinal] => self.check_link_ordinal(attr, span, target),
-                [sym::rustc_confusables] => self.check_confusables(attr, target),
-                [sym::rustc_safe_intrinsic] => {
+                [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target),
+                [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target),
+                [sym::rustc_const_unstable, ..]
+                | [sym::rustc_const_stable, ..]
+                | [sym::unstable, ..]
+                | [sym::stable, ..]
+                | [sym::rustc_allowed_through_unstable_modules, ..]
+                | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target),
+                [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
+                [sym::rustc_confusables, ..] => self.check_confusables(attr, target),
+                [sym::rustc_safe_intrinsic, ..] => {
                     self.check_rustc_safe_intrinsic(hir_id, attr, span, target)
                 }
-                _ => true,
-            };
-
-            // lint-only checks
-            match attr.name_or_empty() {
-                sym::cold => self.check_cold(hir_id, attr, span, target),
-                sym::link => self.check_link(hir_id, attr, span, target),
-                sym::link_name => self.check_link_name(hir_id, attr, span, target),
-                sym::link_section => self.check_link_section(hir_id, attr, span, target),
-                sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
-                sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
-                sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
-                sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
-                sym::macro_export => self.check_macro_export(hir_id, attr, target),
-                sym::ignore | sym::should_panic => {
+                [sym::cold, ..] => self.check_cold(hir_id, attr, span, target),
+                [sym::link, ..] => self.check_link(hir_id, attr, span, target),
+                [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
+                [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
+                [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
+                [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target),
+                [sym::macro_use, ..] | [sym::macro_escape, ..] => {
+                    self.check_macro_use(hir_id, attr, target)
+                }
+                [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
+                [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
+                [sym::ignore, ..] | [sym::should_panic, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Fn)
                 }
-                sym::automatically_derived => {
+                [sym::automatically_derived, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Impl)
                 }
-                sym::no_implicit_prelude => {
+                [sym::no_implicit_prelude, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Mod)
                 }
-                sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
-                sym::proc_macro => {
+                [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id),
+                [sym::proc_macro, ..] => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
                 }
-                sym::proc_macro_attribute => {
+                [sym::proc_macro_attribute, ..] => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
                 }
-                sym::proc_macro_derive => {
+                [sym::proc_macro_derive, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Fn);
                     self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
                 }
-                _ => {}
+                [sym::coroutine, ..] => {
+                    self.check_coroutine(attr, target);
+                }
+                [
+                    // ok
+                    sym::allow
+                    | sym::expect
+                    | sym::warn
+                    | sym::deny
+                    | sym::forbid
+                    | sym::cfg
+                    | sym::cfg_attr
+                    // need to be fixed
+                    | sym::cfi_encoding // FIXME(cfi_encoding)
+                    | sym::may_dangle // FIXME(dropck_eyepatch)
+                    | sym::pointee // FIXME(derive_smart_pointer)
+                    | sym::linkage // FIXME(linkage)
+                    | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
+                    | sym::used // handled elsewhere to restrict to static items
+                    | sym::repr // handled elsewhere to restrict to type decls items
+                    | sym::instruction_set // broken on stable!!!
+                    | sym::windows_subsystem // broken on stable!!!
+                    | sym::patchable_function_entry // FIXME(patchable_function_entry)
+                    | sym::deprecated_safe // FIXME(deprecated_safe)
+                    // internal
+                    | sym::prelude_import
+                    | sym::panic_handler
+                    | sym::allow_internal_unsafe
+                    | sym::fundamental
+                    | sym::lang
+                    | sym::needs_allocator
+                    | sym::default_lib_allocator
+                    | sym::start
+                    | sym::custom_mir,
+                    ..
+                ] => {}
+                [name, ..] => {
+                    match BUILTIN_ATTRIBUTE_MAP.get(name) {
+                        // checked below
+                        Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
+                        Some(_) => {
+                            // FIXME: differentiate between unstable and internal attributes just
+                            // like we do with features instead of just accepting `rustc_`
+                            // attributes by name. That should allow trimming the above list, too.
+                            if !name.as_str().starts_with("rustc_") {
+                                span_bug!(
+                                    attr.span,
+                                    "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
+                                )
+                            }
+                        }
+                        None => (),
+                    }
+                }
+                [] => unreachable!(),
             }
 
             let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
@@ -296,7 +350,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
-    fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool {
+    fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) {
         if !matches!(target, Target::Impl) {
             self.tcx.emit_node_span_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
@@ -305,16 +359,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 errors::IncorrectDoNotRecommendLocation,
             );
         }
-        true
     }
 
     /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
-    fn check_diagnostic_on_unimplemented(
-        &self,
-        attr_span: Span,
-        hir_id: HirId,
-        target: Target,
-    ) -> bool {
+    fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
         if !matches!(target, Target::Trait) {
             self.tcx.emit_node_span_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
@@ -323,72 +371,91 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 DiagnosticOnUnimplementedOnlyForTraits,
             );
         }
-        true
     }
 
-    /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
-    fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+    /// Checks if an `#[inline]` is applied to a function or a closure.
+    fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
         match target {
             Target::Fn
             | Target::Closure
-            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
             Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
                     attr.span,
                     errors::IgnoredInlineAttrFnProto,
-                );
-                true
+                )
             }
             // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
             // just a lint, because we previously erroneously allowed it and some crates used it
             // accidentally, to be compatible with crates depending on them, we can't throw an
             // error here.
-            Target::AssocConst => {
-                self.tcx.emit_node_span_lint(
-                    UNUSED_ATTRIBUTES,
-                    hir_id,
-                    attr.span,
-                    errors::IgnoredInlineAttrConstants,
-                );
-                true
-            }
+            Target::AssocConst => self.tcx.emit_node_span_lint(
+                UNUSED_ATTRIBUTES,
+                hir_id,
+                attr.span,
+                errors::IgnoredInlineAttrConstants,
+            ),
             // FIXME(#80564): Same for fields, arms, and macro defs
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
-                true
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline")
             }
             _ => {
                 self.dcx().emit_err(errors::InlineNotFnOrClosure {
                     attr_span: attr.span,
                     defn_span: span,
                 });
-                false
             }
         }
     }
 
     /// Checks that `#[coverage(..)]` is applied to a function/closure/method,
     /// or to an impl block or module.
-    fn check_coverage(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_coverage(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
             Target::Fn
             | Target::Closure
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
             | Target::Impl
-            | Target::Mod => true,
+            | Target::Mod => {}
 
             _ => {
                 self.dcx().emit_err(errors::CoverageNotFnOrClosure {
                     attr_span: attr.span,
                     defn_span: span,
                 });
-                false
             }
         }
     }
 
+    /// Checks that `#[optimize(..)]` is applied to a function/closure/method,
+    /// or to an impl block or module.
+    // FIXME(#128488): this should probably be elevated to an error?
+    fn check_optimize(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+        match target {
+            Target::Fn
+            | Target::Closure
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
+            | Target::Impl
+            | Target::Mod => {}
+
+            _ => {
+                self.tcx.emit_node_span_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::OptimizeNotFnOrClosure,
+                );
+            }
+        }
+    }
+
+    /// Checks that `#[no_sanitize(..)]` is applied to a function or method.
+    fn check_no_sanitize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+        self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+    }
+
     fn check_generic_attr(
         &self,
         hir_id: HirId,
@@ -417,7 +484,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         span: Span,
         target: Target,
         attrs: &[Attribute],
-    ) -> bool {
+    ) {
         // many attributes don't make sense in combination with #[naked].
         // Notable attributes that are incompatible with `#[naked]` are:
         //
@@ -460,6 +527,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Target::Fn
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
                 for other_attr in attrs {
+                    // this covers "sugared doc comments" of the form `/// ...`
+                    // it does not cover `#[doc = "..."]`, which is handled below
+                    if other_attr.is_doc_comment() {
+                        continue;
+                    }
+
                     if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) {
                         self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
                             span: other_attr.span,
@@ -467,19 +540,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             attr: other_attr.name_or_empty(),
                         });
 
-                        return false;
+                        return;
                     }
                 }
-
-                true
             }
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[naked]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
-                true
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked")
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
@@ -487,7 +557,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
-                false
             }
         }
     }
@@ -499,17 +568,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         match target {
             Target::Fn
-            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
-                false
             }
         }
     }
@@ -535,19 +603,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if `#[collapse_debuginfo]` is applied to a macro.
-    fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::MacroDef => true,
+            Target::MacroDef => {}
             _ => {
                 self.tcx
                     .dcx()
                     .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
-                false
             }
         }
     }
 
-    /// Checks if a `#[track_caller]` is applied to a function. Returns `true` if valid.
+    /// Checks if a `#[track_caller]` is applied to a function.
     fn check_track_caller(
         &self,
         hir_id: HirId,
@@ -555,7 +622,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attrs: &[Attribute],
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         match target {
             Target::Fn => {
                 // `#[track_caller]` is not valid on weak lang items because they are called via
@@ -571,12 +638,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         name: lang_item,
                         sig_span: sig.span,
                     });
-                    false
-                } else {
-                    true
                 }
             }
-            Target::Method(..) | Target::ForeignFn | Target::Closure => true,
+            Target::Method(..) | Target::ForeignFn | Target::Closure => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[track_caller]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
@@ -585,7 +649,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 for attr in attrs {
                     self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
                 }
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::TrackedCallerWrongLocation {
@@ -593,62 +656,51 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
-                false
             }
         }
     }
 
-    /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
-    fn check_non_exhaustive(
-        &self,
-        hir_id: HirId,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
+    fn check_non_exhaustive(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Struct | Target::Enum | Target::Variant => true,
+            Target::Struct | Target::Enum | Target::Variant => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[non_exhaustive]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
                     attr_span: attr.span,
                     defn_span: span,
                 });
-                false
             }
         }
     }
 
-    /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
-    fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+    /// Checks if the `#[marker]` attribute on an `item` is valid.
+    fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Trait => true,
+            Target::Trait => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[marker]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
                     attr_span: attr.span,
                     defn_span: span,
                 });
-                false
             }
         }
     }
 
-    /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
+    /// Checks if the `#[target_feature]` attribute on `item` is valid.
     fn check_target_feature(
         &self,
         hir_id: HirId,
@@ -656,7 +708,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         span: Span,
         target: Target,
         attrs: &[Attribute],
-    ) -> bool {
+    ) {
         match target {
             Target::Fn => {
                 // `#[target_feature]` is not allowed in lang items.
@@ -673,12 +725,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         name: lang_item,
                         sig_span: sig.span,
                     });
-                    false
-                } else {
-                    true
                 }
             }
-            Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+            Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
             // FIXME: #[target_feature] was previously erroneously allowed on statements and some
             // crates used this, so only emit a warning.
             Target::Statement => {
@@ -688,7 +737,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     attr.span,
                     errors::TargetFeatureOnStatement,
                 );
-                true
             }
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[target_feature]` attribute with just a lint, because we previously
@@ -696,7 +744,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
@@ -704,21 +751,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
-                false
             }
         }
     }
 
-    /// Checks if the `#[thread_local]` attribute on `item` is valid. Returns `true` if valid.
-    fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    /// Checks if the `#[thread_local]` attribute on `item` is valid.
+    fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::ForeignStatic | Target::Static => true,
+            Target::ForeignStatic | Target::Static => {}
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
                     attr_span: attr.span,
                     defn_span: span,
                 });
-                false
             }
         }
     }
@@ -735,14 +780,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         target: Target,
         is_list: bool,
         aliases: &mut FxHashMap<String, Span>,
-    ) -> bool {
+    ) {
         let tcx = self.tcx;
         let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
         let attr_str =
             &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
         if doc_alias == kw::Empty {
             tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
-            return false;
+            return;
         }
 
         let doc_alias_str = doc_alias.as_str();
@@ -751,11 +796,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
         {
             tcx.dcx().emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
-            return false;
+            return;
         }
         if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
             tcx.dcx().emit_err(errors::DocAliasStartEnd { span, attr_str });
-            return false;
+            return;
         }
 
         let span = meta.span();
@@ -780,7 +825,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 }
             }
             // we check the validity of params elsewhere
-            Target::Param => return false,
+            Target::Param => return,
             Target::Expression
             | Target::Statement
             | Target::Arm
@@ -813,12 +858,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::ExprField => None,
         } {
             tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location });
-            return false;
+            return;
         }
         let item_name = self.tcx.hir().name(hir_id);
         if item_name == doc_alias {
             tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str });
-            return false;
+            return;
         }
         if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
             self.tcx.emit_node_span_lint(
@@ -828,7 +873,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 errors::DocAliasDuplicated { first_defn: *entry.entry.get() },
             );
         }
-        true
     }
 
     fn check_doc_alias(
@@ -837,46 +881,39 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         hir_id: HirId,
         target: Target,
         aliases: &mut FxHashMap<String, Span>,
-    ) -> bool {
+    ) {
         if let Some(values) = meta.meta_item_list() {
-            let mut errors = 0;
             for v in values {
                 match v.lit() {
                     Some(l) => match l.kind {
                         LitKind::Str(s, _) => {
-                            if !self.check_doc_alias_value(v, s, hir_id, target, true, aliases) {
-                                errors += 1;
-                            }
+                            self.check_doc_alias_value(v, s, hir_id, target, true, aliases);
                         }
                         _ => {
                             self.tcx
                                 .dcx()
                                 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
-                            errors += 1;
                         }
                     },
                     None => {
                         self.tcx
                             .dcx()
                             .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
-                        errors += 1;
                     }
                 }
             }
-            errors == 0
         } else if let Some(doc_alias) = meta.value_str() {
             self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
         } else {
             self.dcx().emit_err(errors::DocAliasMalformed { span: meta.span() });
-            false
         }
     }
 
-    fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+    fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) {
         let doc_keyword = meta.value_str().unwrap_or(kw::Empty);
         if doc_keyword == kw::Empty {
             self.doc_attr_str_error(meta, "keyword");
-            return false;
+            return;
         }
         let item_kind = match self.tcx.hir_node(hir_id) {
             hir::Node::Item(item) => Some(&item.kind),
@@ -886,12 +923,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Some(ItemKind::Mod(module)) => {
                 if !module.item_ids.is_empty() {
                     self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
-                    return false;
+                    return;
                 }
             }
             _ => {
                 self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() });
-                return false;
+                return;
             }
         }
         if !rustc_lexer::is_ident(doc_keyword.as_str()) {
@@ -899,12 +936,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
                 doc_keyword,
             });
-            return false;
         }
-        true
     }
 
-    fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+    fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) {
         let item_kind = match self.tcx.hir_node(hir_id) {
             hir::Node::Item(item) => Some(&item.kind),
             _ => None,
@@ -919,18 +954,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     };
                 if !is_valid {
                     self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
-                    return false;
                 }
             }
             _ => {
                 self.dcx().emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
-                return false;
             }
         }
-        true
     }
 
-    /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes. Returns `true` if valid.
+    /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes.
     ///
     /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
     /// if there are conflicting attributes for one item.
@@ -946,7 +978,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         hir_id: HirId,
         target: Target,
         specified_inline: &mut Option<(bool, Span)>,
-    ) -> bool {
+    ) {
         match target {
             Target::Use | Target::ExternCrate => {
                 let do_inline = meta.name_or_empty() == sym::inline;
@@ -959,12 +991,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             fluent::passes_doc_inline_conflict_second,
                         );
                         self.dcx().emit_err(errors::DocKeywordConflict { spans });
-                        return false;
                     }
-                    true
                 } else {
                     *specified_inline = Some((do_inline, meta.span()));
-                    true
                 }
             }
             _ => {
@@ -978,7 +1007,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             .then(|| self.tcx.hir().span(hir_id)),
                     },
                 );
-                false
             }
         }
     }
@@ -989,7 +1017,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         meta: &NestedMetaItem,
         hir_id: HirId,
         target: Target,
-    ) -> bool {
+    ) {
         if target != Target::ExternCrate {
             self.tcx.emit_node_span_lint(
                 INVALID_DOC_ATTRIBUTES,
@@ -1001,7 +1029,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         .then(|| self.tcx.hir().span(hir_id)),
                 },
             );
-            return false;
+            return;
         }
 
         if self.tcx.extern_mod_stmt_cnum(hir_id.owner).is_none() {
@@ -1015,10 +1043,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         .then(|| self.tcx.hir().span(hir_id)),
                 },
             );
-            return false;
         }
-
-        true
     }
 
     /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
@@ -1063,8 +1088,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
     /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if
     /// valid.
-    fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
-        let mut is_valid = true;
+    fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) {
         if let Some(metas) = meta.meta_item_list() {
             for i_meta in metas {
                 match (i_meta.name_or_empty(), i_meta.meta_item()) {
@@ -1078,7 +1102,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                                 path: rustc_ast_pretty::pprust::path_to_string(&m.path),
                             },
                         );
-                        is_valid = false;
                     }
                     (_, None) => {
                         self.tcx.emit_node_span_lint(
@@ -1087,7 +1110,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             i_meta.span(),
                             errors::DocTestLiteral,
                         );
-                        is_valid = false;
                     }
                 }
             }
@@ -1098,34 +1120,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 meta.span(),
                 errors::DocTestTakesList,
             );
-            is_valid = false;
         }
-        is_valid
     }
 
     /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
-    /// Returns `true` if valid.
-    fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
-        if meta.meta_item_list().is_some() {
-            true
-        } else {
+    ///
+    fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) {
+        if meta.meta_item_list().is_none() {
             self.tcx.emit_node_span_lint(
                 INVALID_DOC_ATTRIBUTES,
                 hir_id,
                 meta.span(),
                 errors::DocCfgHideTakesList,
             );
-            false
         }
     }
 
-    /// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
+    /// Runs various checks on `#[doc]` attributes.
     ///
     /// `specified_inline` should be initialized to `None` and kept for the scope
     /// of one item. Read the documentation of [`check_doc_inline`] for more information.
     ///
     /// [`check_doc_inline`]: Self::check_doc_inline
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_doc_attrs(
         &self,
         attr: &Attribute,
@@ -1133,34 +1149,35 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         target: Target,
         specified_inline: &mut Option<(bool, Span)>,
         aliases: &mut FxHashMap<String, Span>,
-    ) -> bool {
-        let mut is_valid = true;
-
+    ) {
         if let Some(mi) = attr.meta()
             && let Some(list) = mi.meta_item_list()
         {
             for meta in list {
                 if let Some(i_meta) = meta.meta_item() {
                     match i_meta.name_or_empty() {
-                        sym::alias
-                            if !self.check_attr_not_crate_level(meta, hir_id, "alias")
-                                || !self.check_doc_alias(meta, hir_id, target, aliases) =>
-                        {
-                            is_valid = false
+                        sym::alias => {
+                            if self.check_attr_not_crate_level(meta, hir_id, "alias") {
+                                self.check_doc_alias(meta, hir_id, target, aliases);
+                            }
                         }
 
-                        sym::keyword
-                            if !self.check_attr_not_crate_level(meta, hir_id, "keyword")
-                                || !self.check_doc_keyword(meta, hir_id) =>
-                        {
-                            is_valid = false
+                        sym::keyword => {
+                            if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
+                                self.check_doc_keyword(meta, hir_id);
+                            }
+                        }
+
+                        sym::fake_variadic => {
+                            if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
+                                self.check_doc_fake_variadic(meta, hir_id);
+                            }
                         }
 
-                        sym::fake_variadic
-                            if !self.check_attr_not_crate_level(meta, hir_id, "fake_variadic")
-                                || !self.check_doc_fake_variadic(meta, hir_id) =>
-                        {
-                            is_valid = false
+                        sym::test => {
+                            if self.check_attr_crate_level(attr, meta, hir_id) {
+                                self.check_test_attr(meta, hir_id);
+                            }
                         }
 
                         sym::html_favicon_url
@@ -1168,78 +1185,46 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         | sym::html_playground_url
                         | sym::issue_tracker_base_url
                         | sym::html_root_url
-                        | sym::html_no_source
-                        | sym::test
-                        | sym::rust_logo
-                            if !self.check_attr_crate_level(attr, meta, hir_id) =>
-                        {
-                            is_valid = false;
+                        | sym::html_no_source => {
+                            self.check_attr_crate_level(attr, meta, hir_id);
                         }
 
-                        sym::cfg_hide
-                            if !self.check_attr_crate_level(attr, meta, hir_id)
-                                || !self.check_doc_cfg_hide(meta, hir_id) =>
-                        {
-                            is_valid = false;
+                        sym::cfg_hide => {
+                            if self.check_attr_crate_level(attr, meta, hir_id) {
+                                self.check_doc_cfg_hide(meta, hir_id);
+                            }
                         }
 
-                        sym::inline | sym::no_inline
-                            if !self.check_doc_inline(
-                                attr,
-                                meta,
-                                hir_id,
-                                target,
-                                specified_inline,
-                            ) =>
-                        {
-                            is_valid = false;
+                        sym::inline | sym::no_inline => {
+                            self.check_doc_inline(attr, meta, hir_id, target, specified_inline)
                         }
 
-                        sym::masked if !self.check_doc_masked(attr, meta, hir_id, target) => {
-                            is_valid = false;
-                        }
+                        sym::masked => self.check_doc_masked(attr, meta, hir_id, target),
 
                         // no_default_passes: deprecated
                         // passes: deprecated
                         // plugins: removed, but rustdoc warns about it itself
-                        sym::alias
-                        | sym::cfg
-                        | sym::cfg_hide
+                        sym::cfg
                         | sym::hidden
-                        | sym::html_favicon_url
-                        | sym::html_logo_url
-                        | sym::html_no_source
-                        | sym::html_playground_url
-                        | sym::html_root_url
-                        | sym::inline
-                        | sym::issue_tracker_base_url
-                        | sym::keyword
-                        | sym::masked
                         | sym::no_default_passes
-                        | sym::no_inline
                         | sym::notable_trait
                         | sym::passes
-                        | sym::plugins
-                        | sym::fake_variadic => {}
+                        | sym::plugins => {}
 
                         sym::rust_logo => {
-                            if !self.tcx.features().rustdoc_internals {
+                            if self.check_attr_crate_level(attr, meta, hir_id)
+                                && !self.tcx.features().rustdoc_internals
+                            {
                                 feature_err(
                                     &self.tcx.sess,
                                     sym::rustdoc_internals,
                                     meta.span(),
-                                    "the `#[doc(rust_logo)]` attribute is used for Rust branding",
+                                    fluent::passes_doc_rust_logo,
                                 )
                                 .emit();
                             }
                         }
 
-                        sym::test => {
-                            if !self.check_test_attr(meta, hir_id) {
-                                is_valid = false;
-                            }
-                        }
-
                         _ => {
                             let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
                             if i_meta.has_name(sym::spotlight) {
@@ -1281,7 +1266,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                                     errors::DocTestUnknownAny { path },
                                 );
                             }
-                            is_valid = false;
                         }
                     }
                 } else {
@@ -1291,79 +1275,60 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         meta.span(),
                         errors::DocInvalid,
                     );
-                    is_valid = false;
                 }
             }
         }
-
-        is_valid
     }
 
     /// Warns against some misuses of `#[pass_by_value]`
-    fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Struct | Target::Enum | Target::TyAlias => true,
+            Target::Struct | Target::Enum | Target::TyAlias => {}
             _ => {
                 self.dcx().emit_err(errors::PassByValue { attr_span: attr.span, span });
-                false
             }
         }
     }
 
-    fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Method(MethodKind::Inherent) => true,
+            Target::Method(MethodKind::Inherent) => {}
             _ => {
                 self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
-                false
             }
         }
     }
 
-    fn check_has_incoherent_inherent_impls(
-        &self,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {
-                true
-            }
+            Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {}
             _ => {
                 self.tcx
                     .dcx()
                     .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span });
-                false
             }
         }
     }
 
-    fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) -> bool {
+    fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) {
         if target != Target::ForeignFn {
             self.dcx().emit_err(errors::FfiPureInvalidTarget { attr_span });
-            return false;
+            return;
         }
         if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
             // `#[ffi_const]` functions cannot be `#[ffi_pure]`
             self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span });
-            false
-        } else {
-            true
         }
     }
 
-    fn check_ffi_const(&self, attr_span: Span, target: Target) -> bool {
-        if target == Target::ForeignFn {
-            true
-        } else {
+    fn check_ffi_const(&self, attr_span: Span, target: Target) {
+        if target != Target::ForeignFn {
             self.dcx().emit_err(errors::FfiConstInvalidTarget { attr_span });
-            false
         }
     }
 
     /// Warns against some misuses of `#[must_use]`
-    fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool {
+    fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         if !matches!(
             target,
             Target::Fn
@@ -1396,23 +1361,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 errors::MustUseNoEffect { article, target },
             );
         }
-
-        // For now, its always valid
-        true
     }
 
-    /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
-    fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    /// Checks if `#[must_not_suspend]` is applied to a function.
+    fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
+            Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
             _ => {
                 self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
-                false
             }
         }
     }
 
-    /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
+    /// Checks if `#[cold]` is applied to a non-function.
     fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
         match target {
             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
@@ -1488,21 +1449,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
-    fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+    /// Checks if `#[no_link]` is applied to an `extern crate`.
+    fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::ExternCrate => true,
+            Target::ExternCrate => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[no_link]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::NoLink { attr_span: attr.span, span });
-                false
             }
         }
     }
@@ -1511,57 +1470,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         matches!(self.tcx.hir_node(hir_id), hir::Node::ImplItem(..))
     }
 
-    /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
-    fn check_export_name(
-        &self,
-        hir_id: HirId,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    /// Checks if `#[export_name]` is applied to a function or static.
+    fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Static | Target::Fn => true,
-            Target::Method(..) if self.is_impl_item(hir_id) => true,
+            Target::Static | Target::Fn => {}
+            Target::Method(..) if self.is_impl_item(hir_id) => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
             // `#[export_name]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::ExportName { attr_span: attr.span, span });
-                false
             }
         }
     }
 
-    fn check_rustc_layout_scalar_valid_range(
-        &self,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) {
         if target != Target::Struct {
             self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
                 attr_span: attr.span,
                 span,
             });
-            return false;
+            return;
         }
 
         let Some(list) = attr.meta_item_list() else {
-            return false;
+            return;
         };
 
-        if matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
-            true
-        } else {
+        if !matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })])
+        {
             self.tcx
                 .dcx()
                 .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
-            false
         }
     }
 
@@ -1573,7 +1517,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         span: Span,
         target: Target,
         item: Option<ItemLike<'_>>,
-    ) -> bool {
+    ) {
         let is_function = matches!(target, Target::Fn);
         if !is_function {
             self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
@@ -1581,12 +1525,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
-            return false;
+            return;
         }
 
         let Some(list) = attr.meta_item_list() else {
             // The attribute form is validated on AST.
-            return false;
+            return;
         };
 
         let Some(ItemLike::Item(Item {
@@ -1604,7 +1548,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         attr_span: attr.span,
                         param_span: param.span,
                     });
-                    return false;
+                    return;
                 }
             }
         }
@@ -1614,7 +1558,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 attr_span: attr.span,
                 generics_span: generics.span,
             });
-            return false;
+            return;
         }
 
         let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
@@ -1627,7 +1571,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         span,
                         arg_count: arg_count as usize,
                     });
-                    return false;
+                    return;
                 }
             } else {
                 invalid_args.push(meta.span());
@@ -1636,9 +1580,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
         if !invalid_args.is_empty() {
             self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
-            false
-        } else {
-            true
         }
     }
 
@@ -1650,7 +1591,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
             self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
@@ -1658,9 +1599,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
-            false
-        } else {
-            true
         }
     }
 
@@ -1672,7 +1610,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         self.check_applied_to_fn_or_method(hir_id, attr, span, target)
     }
 
@@ -1684,60 +1622,49 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         self.check_applied_to_fn_or_method(hir_id, attr, span, target)
     }
 
     /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
-    fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Struct => true,
+            Target::Struct => {}
             _ => {
                 self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span, span });
-                false
             }
         }
     }
 
     /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field.
-    fn check_rustc_lint_opt_deny_field_access(
-        &self,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Field => true,
+            Target::Field => {}
             _ => {
                 self.tcx
                     .dcx()
                     .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span });
-                false
             }
         }
     }
 
     /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
     /// option is passed to the compiler.
-    fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
-        if self.tcx.sess.opts.unstable_opts.query_dep_graph {
-            true
-        } else {
+    fn check_rustc_dirty_clean(&self, attr: &Attribute) {
+        if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
             self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span });
-            false
         }
     }
 
     /// Checks if the attribute is applied to a trait.
-    fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Trait => true,
+            Target::Trait => {}
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
                     attr_span: attr.span,
                     defn_span: span,
                 });
-                false
             }
         }
     }
@@ -1808,7 +1735,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if the `#[repr]` attributes on `item` are valid.
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_repr(
         &self,
         attrs: &[Attribute],
@@ -1865,7 +1791,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             &self.tcx.sess,
                             sym::fn_align,
                             hint.span(),
-                            "`repr(align)` attributes on functions are unstable",
+                            fluent::passes_repr_align_function,
                         )
                         .emit();
                     }
@@ -2035,43 +1961,38 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         span: Span,
         target: Target,
         attrs: &[Attribute],
-    ) -> bool {
+    ) {
         debug!("Checking target: {:?}", target);
         match target {
             Target::Fn => {
                 for attr in attrs {
                     if attr.is_proc_macro_attr() {
                         debug!("Is proc macro attr");
-                        return true;
+                        return;
                     }
                 }
                 debug!("Is not proc macro attr");
-                false
             }
-            Target::MacroDef => true,
+            Target::MacroDef => {}
             // FIXME(#80564): We permit struct fields and match arms to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
-            Target::Field | Target::Arm => {
-                self.inline_attr_str_error_without_macro_def(
-                    hir_id,
-                    attr,
-                    "allow_internal_unstable",
-                );
-                true
-            }
+            Target::Field | Target::Arm => self.inline_attr_str_error_without_macro_def(
+                hir_id,
+                attr,
+                "allow_internal_unstable",
+            ),
             _ => {
                 self.tcx
                     .dcx()
                     .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
-                false
             }
         }
     }
 
     /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
-    fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
+    fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
         // Here we only check that the #[debugger_visualizer] attribute is attached
         // to nothing other than a module. All other checks are done in the
         // `debugger_visualizer` query where they need to be done for decoding
@@ -2080,11 +2001,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Target::Mod => {}
             _ => {
                 self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span });
-                return false;
             }
         }
-
-        true
     }
 
     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
@@ -2095,26 +2013,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         match target {
             Target::Fn | Target::Method(_)
-                if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) =>
-            {
-                true
-            }
+                if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => {}
             // FIXME(#80564): We permit struct fields and match arms to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
-                true
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable")
             }
             _ => {
                 self.tcx
                     .dcx()
                     .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
-                false
             }
         }
     }
@@ -2125,65 +2038,56 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         span: Span,
         target: Target,
-    ) -> bool {
+    ) {
         if let Target::ForeignFn = target
             && let hir::Node::Item(Item {
                 kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic, .. },
                 ..
             }) = self.tcx.parent_hir_node(hir_id)
         {
-            return true;
+            return;
         }
 
         self.dcx().emit_err(errors::RustcSafeIntrinsic { attr_span: attr.span, span });
-        false
     }
 
-    fn check_rustc_std_internal_symbol(
-        &self,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    fn check_rustc_std_internal_symbol(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
-            Target::Fn | Target::Static => true,
+            Target::Fn | Target::Static => {}
             _ => {
                 self.tcx
                     .dcx()
                     .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
-                false
             }
         }
     }
 
-    fn check_stability_promotable(&self, attr: &Attribute, target: Target) -> bool {
+    fn check_stability_promotable(&self, attr: &Attribute, target: Target) {
         match target {
             Target::Expression => {
                 self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span });
-                false
             }
-            _ => true,
+            _ => {}
         }
     }
 
-    fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
+    fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) {
         match target {
-            Target::ForeignFn | Target::ForeignStatic => true,
+            Target::ForeignFn | Target::ForeignStatic => {}
             _ => {
                 self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span });
-                false
             }
         }
     }
 
-    fn check_confusables(&self, attr: &Attribute, target: Target) -> bool {
+    fn check_confusables(&self, attr: &Attribute, target: Target) {
         match target {
             Target::Method(MethodKind::Inherent) => {
                 let Some(meta) = attr.meta() else {
-                    return false;
+                    return;
                 };
                 let ast::MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else {
-                    return false;
+                    return;
                 };
 
                 let mut candidates = Vec::new();
@@ -2197,21 +2101,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                                 hi: meta.span().shrink_to_hi(),
                             },
                         });
-                        return false;
+                        return;
                     };
                     candidates.push(meta_lit.symbol);
                 }
 
                 if candidates.is_empty() {
                     self.dcx().emit_err(errors::EmptyConfusables { span: attr.span });
-                    return false;
                 }
-
-                true
             }
             _ => {
                 self.dcx().emit_err(errors::Confusables { attr_span: attr.span });
-                false
             }
         }
     }
@@ -2311,8 +2211,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             attr.name_or_empty(),
             sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
         ) && let Some(meta) = attr.meta_item_list()
-            && meta.len() == 1
-            && let Some(item) = meta[0].meta_item()
+            && let [meta] = meta.as_slice()
+            && let Some(item) = meta.meta_item()
             && let MetaItemKind::NameValue(_) = &item.kind
             && item.path == sym::reason
         {
@@ -2438,6 +2338,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             self.abort.set(true);
         }
     }
+
+    fn check_coroutine(&self, attr: &Attribute, target: Target) {
+        match target {
+            Target::Closure => return,
+            _ => {
+                self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span });
+            }
+        }
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 3f6eccbd5a5..be6449ea852 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -7,8 +7,6 @@
 //! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
-use rustc_attr as attr;
-use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::hir::nested_filter;
@@ -17,6 +15,7 @@ use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, Span, Symbol};
+use {rustc_attr as attr, rustc_hir as hir};
 
 use crate::errors::SkippingConstChecks;
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 239bc8e7acc..7ae5c904004 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -3,6 +3,8 @@
 // expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else
 // is dead.
 
+use std::mem;
+
 use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
 use hir::ItemKind;
 use rustc_data_structures::unord::UnordSet;
@@ -15,13 +17,12 @@ use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_session::lint::builtin::DEAD_CODE;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::FieldIdx;
-use std::mem;
 
 use crate::errors::{
     ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment,
@@ -43,77 +44,16 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     )
 }
 
-struct Publicness {
-    ty_is_public: bool,
-    ty_and_all_fields_are_public: bool,
-}
-
-impl Publicness {
-    fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self {
-        Self { ty_is_public, ty_and_all_fields_are_public }
-    }
-}
-
-fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
-    match ty.kind {
-        TyKind::Path(hir::QPath::Resolved(_, path)) => {
-            if let Res::Def(def_kind, def_id) = path.res
-                && let Some(local_def_id) = def_id.as_local()
-            {
-                Some((local_def_id, def_kind))
-            } else {
-                None
-            }
-        }
-        TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty),
-        TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty),
-        _ => None,
-    }
-}
-
-fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool {
-    // treat PhantomData and positional ZST as public,
-    // we don't want to lint types which only have them,
-    // cause it's a common way to use such types to check things like well-formedness
-    tcx.adt_def(id).all_fields().all(|field| {
-        let field_type = tcx.type_of(field.did).instantiate_identity();
-        if field_type.is_phantom_data() {
-            return true;
-        }
-        let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
-        if is_positional
-            && tcx
-                .layout_of(tcx.param_env(field.did).and(field_type))
-                .map_or(true, |layout| layout.is_zst())
-        {
-            return true;
-        }
-        field.vis.is_public()
-    })
-}
-
-/// check struct and its fields are public or not,
-/// for enum and union, just check they are public,
-/// and doesn't solve types like &T for now, just skip them
-fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
-    if let Some((def_id, def_kind)) = adt_of(ty) {
-        return match def_kind {
-            DefKind::Enum | DefKind::Union => {
-                let ty_is_public = tcx.visibility(def_id).is_public();
-                Publicness::new(ty_is_public, ty_is_public)
-            }
-            DefKind::Struct => {
-                let ty_is_public = tcx.visibility(def_id).is_public();
-                Publicness::new(
-                    ty_is_public,
-                    ty_is_public && struct_all_fields_are_public(tcx, def_id),
-                )
-            }
-            _ => Publicness::new(true, true),
-        };
+fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool {
+    if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
+        && let Res::Def(def_kind, def_id) = path.res
+        && def_id.is_local()
+        && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
+    {
+        tcx.visibility(def_id).is_public()
+    } else {
+        true
     }
-
-    Publicness::new(true, true)
 }
 
 /// Determine if a work from the worklist is coming from a `#[allow]`
@@ -169,10 +109,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
 
     fn handle_res(&mut self, res: Res) {
         match res {
-            Res::Def(
-                DefKind::Const | DefKind::AssocConst | DefKind::AssocTy | DefKind::TyAlias,
-                def_id,
-            ) => {
+            Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => {
                 self.check_def_id(def_id);
             }
             _ if self.in_pat => {}
@@ -291,10 +228,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         pats: &[hir::PatField<'_>],
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
-            ty::Adt(adt, _) => {
-                self.check_def_id(adt.did());
-                adt.variant_of_res(res)
-            }
+            ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => span_bug!(lhs.span, "non-ADT in struct pattern"),
         };
         for pat in pats {
@@ -314,10 +248,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         dotdot: hir::DotDotPos,
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
-            ty::Adt(adt, _) => {
-                self.check_def_id(adt.did());
-                adt.variant_of_res(res)
-            }
+            ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => {
                 self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
                 return;
@@ -422,6 +353,31 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 return false;
             }
 
+            // don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
+            // cause external crate may call such methods to construct values of these types
+            if let Some(local_impl_of) = impl_of.as_local()
+                && let Some(local_def_id) = def_id.as_local()
+                && let Some(fn_sig) =
+                    self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
+                && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
+                && let TyKind::Path(hir::QPath::Resolved(_, path)) =
+                    self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
+                && let Res::Def(def_kind, did) = path.res
+            {
+                match def_kind {
+                    // for example, #[derive(Default)] pub struct T(i32);
+                    // external crate can call T::default() to construct T,
+                    // so that don't ignore impl Default for pub Enum and Structs
+                    DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
+                        return false;
+                    }
+                    // don't ignore impl Default for Enums,
+                    // cause we don't know which variant is constructed
+                    DefKind::Enum => return false,
+                    _ => (),
+                };
+            }
+
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
                 && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
             {
@@ -464,7 +420,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     intravisit::walk_item(self, item)
                 }
                 hir::ItemKind::ForeignMod { .. } => {}
-                hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => {
+                hir::ItemKind::Trait(..) => {
                     for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) {
                         if let Some(local_def_id) = impl_def_id.as_local()
                             && let ItemKind::Impl(impl_ref) =
@@ -477,12 +433,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                             intravisit::walk_path(self, impl_ref.of_trait.unwrap().path);
                         }
                     }
-                    // mark assoc ty live if the trait is live
-                    for trait_item in trait_item_refs {
-                        if let hir::AssocItemKind::Type = trait_item.kind {
-                            self.check_def_id(trait_item.id.owner_id.to_def_id());
-                        }
-                    }
+
                     intravisit::walk_item(self, item)
                 }
                 _ => intravisit::walk_item(self, item),
@@ -499,12 +450,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                             && let ItemKind::Impl(impl_ref) =
                                 self.tcx.hir().expect_item(local_impl_id).kind
                         {
-                            if !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
-                                .ty_and_all_fields_are_public
+                            if !matches!(trait_item.kind, hir::TraitItemKind::Type(..))
+                                && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
                             {
-                                // skip impl-items of non pure pub ty,
-                                // cause we don't know the ty is constructed or not,
-                                // check these later in `solve_rest_impl_items`
+                                // skip methods of private ty,
+                                // they would be solved in `solve_rest_impl_items`
                                 continue;
                             }
 
@@ -579,25 +529,28 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     }
 
     fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool {
-        if let Some((local_def_id, def_kind)) =
-            adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty)
+        if let TyKind::Path(hir::QPath::Resolved(_, path)) =
+            self.tcx.hir().item(impl_id).expect_impl().self_ty.kind
+            && let Res::Def(def_kind, def_id) = path.res
+            && let Some(local_def_id) = def_id.as_local()
             && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
         {
+            if self.tcx.visibility(impl_item_id).is_public() {
+                // for the public method, we don't know the trait item is used or not,
+                // so we mark the method live if the self is used
+                return self.live_symbols.contains(&local_def_id);
+            }
+
             if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
                 && let Some(local_id) = trait_item_id.as_local()
             {
-                // for the local impl item, we can know the trait item is used or not,
+                // for the private method, we can know the trait item is used or not,
                 // so we mark the method live if the self is used and the trait item is used
-                self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id)
-            } else {
-                // for the foreign method and inherent pub method,
-                // we don't know the trait item or the method is used or not,
-                // so we mark the method live if the self is used
-                self.live_symbols.contains(&local_def_id)
+                return self.live_symbols.contains(&local_id)
+                    && self.live_symbols.contains(&local_def_id);
             }
-        } else {
-            false
         }
+        false
     }
 }
 
@@ -683,9 +636,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
                 self.handle_field_pattern_match(pat, res, fields);
             }
             PatKind::Path(ref qpath) => {
-                if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() {
-                    self.check_def_id(adt.did());
-                }
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_res(res);
             }
@@ -822,9 +772,7 @@ fn check_item<'tcx>(
                 .iter()
                 .filter_map(|def_id| def_id.as_local());
 
-            let self_ty = tcx.hir().item(id).expect_impl().self_ty;
-            let Publicness { ty_is_public, ty_and_all_fields_are_public } =
-                ty_ref_to_pub_struct(tcx, self_ty);
+            let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
 
             // And we access the Map here to get HirId from LocalDefId
             for local_def_id in local_def_ids {
@@ -840,19 +788,18 @@ fn check_item<'tcx>(
                 // for trait impl blocks,
                 // mark the method live if the self_ty is public,
                 // or the method is public and may construct self
-                if tcx.visibility(local_def_id).is_public()
-                    && (ty_and_all_fields_are_public || (ty_is_public && may_construct_self))
+                if of_trait
+                    && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
+                        || tcx.visibility(local_def_id).is_public()
+                            && (ty_is_pub || may_construct_self))
                 {
-                    // if the impl item is public,
-                    // and the ty may be constructed or can be constructed in foreign crates,
-                    // mark the impl item live
                     worklist.push((local_def_id, ComesFromAllowExpect::No));
                 } else if let Some(comes_from_allow) =
                     has_allow_dead_code_or_lang_attr(tcx, local_def_id)
                 {
                     worklist.push((local_def_id, comes_from_allow));
-                } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
-                    // private impl items of traits || public impl items not constructs self
+                } else if of_trait {
+                    // private method || public method not constructs self
                     unsolved_impl_items.push((id, local_def_id));
                 }
             }
@@ -878,13 +825,10 @@ fn check_trait_item(
     worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
     id: hir::TraitItemId,
 ) {
-    use hir::TraitItemKind::{Const, Fn, Type};
-    if matches!(
-        tcx.def_kind(id.owner_id),
-        DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn
-    ) {
+    use hir::TraitItemKind::{Const, Fn};
+    if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
         let trait_item = tcx.hir().trait_item(id);
-        if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..))
+        if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..))
             && let Some(comes_from_allow) =
                 has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
         {
@@ -922,14 +866,6 @@ fn create_and_seed_worklist(
             effective_vis
                 .is_public_at_level(Level::Reachable)
                 .then_some(id)
-                .filter(|&id|
-                    // checks impls, impl-items and pub structs with all public fields later
-                    match tcx.def_kind(id) {
-                        DefKind::Impl { .. } => false,
-                        DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
-                        DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
-                        _ => true
-                    })
                 .map(|id| (id, ComesFromAllowExpect::No))
         })
         // Seed entry point
@@ -1213,7 +1149,6 @@ impl<'tcx> DeadVisitor<'tcx> {
         }
         match self.tcx.def_kind(def_id) {
             DefKind::AssocConst
-            | DefKind::AssocTy
             | DefKind::AssocFn
             | DefKind::Fn
             | DefKind::Static { .. }
@@ -1255,14 +1190,10 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
             || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
         {
             for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
-                // We have diagnosed unused assocs in traits
+                // We have diagnosed unused methods in traits
                 if matches!(def_kind, DefKind::Impl { of_trait: true })
-                    && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn)
-                    // skip unused public inherent methods,
-                    // cause we have diagnosed unconstructed struct
-                    || matches!(def_kind, DefKind::Impl { of_trait: false })
-                        && tcx.visibility(def_id).is_public()
-                        && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public
+                    && tcx.def_kind(def_id) == DefKind::AssocFn
+                    || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
                 {
                     continue;
                 }
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 96893e58549..5d871bacb1d 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -3,11 +3,9 @@
 use rustc_ast::Attribute;
 use rustc_data_structures::sync::Lrc;
 use rustc_expand::base::resolve_path;
-use rustc_middle::{
-    middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType},
-    query::{LocalCrate, Providers},
-    ty::TyCtxt,
-};
+use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_middle::query::{LocalCrate, Providers};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::sym;
 
@@ -21,9 +19,7 @@ impl DebuggerVisualizerCollector<'_> {
                 return;
             };
 
-            let hint = if hints.len() == 1 {
-                &hints[0]
-            } else {
+            let [hint] = hints.as_slice() else {
                 self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
                 return;
             };
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 906ecdfe5ab..659281c5e71 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -12,8 +12,7 @@
 use rustc_ast as ast;
 use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::OwnerId;
-use rustc_middle::query::LocalCrate;
-use rustc_middle::query::Providers;
+use rustc_middle::query::{LocalCrate, Providers};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index b43c8282db1..ecb345bb51a 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -6,8 +6,8 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{sigpipe, CrateType, EntryFnType};
-use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+use rustc_session::config::{sigpipe, CrateType, EntryFnType, RemapPathScopeComponents};
+use rustc_session::RemapFileNameExt;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 
@@ -106,7 +106,6 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     }
 }
 
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
     if let Some((def_id, _)) = visitor.start_fn {
         Some((def_id.to_def_id(), EntryFnType::Start))
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index b195ba973ce..36dfc40e762 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,13 +1,11 @@
-use std::{
-    io::Error,
-    path::{Path, PathBuf},
-};
+use std::io::Error;
+use std::path::{Path, PathBuf};
 
-use crate::fluent_generated as fluent;
 use rustc_ast::Label;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee,
-    Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
+    Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
+    MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir::{self as hir, ExprKind, Target};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -15,6 +13,7 @@ use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
 use crate::check_attr::ProcMacroKind;
+use crate::fluent_generated as fluent;
 use crate::lang_items::Duplicate;
 
 #[derive(LintDiagnostic)]
@@ -69,6 +68,10 @@ pub struct CoverageNotFnOrClosure {
     pub defn_span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(passes_optimize_not_fn_or_closure)]
+pub struct OptimizeNotFnOrClosure;
+
 #[derive(Diagnostic)]
 #[diag(passes_should_be_applied_to_fn)]
 pub struct AttrShouldBeAppliedToFn {
@@ -634,6 +637,13 @@ pub struct Confusables {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_coroutine_on_non_closure)]
+pub struct CoroutineOnNonClosure {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_empty_confusables)]
 pub(crate) struct EmptyConfusables {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index fb7529d93ed..38e8c3cd12d 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -2,13 +2,11 @@
 // pieces of AST and HIR. The resulting numbers are good approximations but not
 // completely accurate (some things might be counted twice, others missed).
 
-use rustc_ast::visit as ast_visit;
 use rustc_ast::visit::BoundKind;
-use rustc_ast::{self as ast, AttrId, NodeId};
+use rustc_ast::{self as ast, visit as ast_visit, AttrId, NodeId};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
-use rustc_hir::intravisit as hir_visit;
-use rustc_hir::HirId;
+use rustc_hir::{intravisit as hir_visit, HirId};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::common::to_readable_str;
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index b3722e99e16..3f1be87a73f 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -7,23 +7,22 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
-use crate::errors::{
-    DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
-};
-use crate::weak_lang_items;
-
 use rustc_ast as ast;
 use rustc_ast::visit;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::{extract, GenericRequirement};
 use rustc_hir::{LangItem, LanguageItems, MethodKind, Target};
+use rustc_middle::query::Providers;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::cstore::ExternCrate;
 use rustc_span::symbol::kw::Empty;
 use rustc_span::Span;
 
-use rustc_middle::query::Providers;
+use crate::errors::{
+    DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
+};
+use crate::weak_lang_items;
 
 pub(crate) enum Duplicate {
     Plain,
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 6f59c782e06..e1bc770d817 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -9,7 +9,8 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
-use rustc_trait_selection::{infer::TyCtxtInferExt, traits};
+use rustc_trait_selection::infer::TyCtxtInferExt;
+use rustc_trait_selection::traits;
 
 use crate::errors::{
     LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf,
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index dfa7dfa3398..d3b85da4630 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -81,10 +81,9 @@
 //! We generate various special nodes for various, well, special purposes.
 //! These are described in the `Liveness` struct.
 
-use crate::errors;
-
-use self::LiveNodeKind::*;
-use self::VarKind::*;
+use std::io;
+use std::io::prelude::*;
+use std::rc::Rc;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
@@ -99,11 +98,12 @@ use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, Span};
-use std::io;
-use std::io::prelude::*;
-use std::rc::Rc;
 use tracing::{debug, instrument};
 
+use self::LiveNodeKind::*;
+use self::VarKind::*;
+use crate::errors;
+
 mod rwu_table;
 
 rustc_index::newtype_index! {
diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs
index 053bf5c234a..6e2f976e5b0 100644
--- a/compiler/rustc_passes/src/liveness/rwu_table.rs
+++ b/compiler/rustc_passes/src/liveness/rwu_table.rs
@@ -1,6 +1,7 @@
-use crate::liveness::{LiveNode, Variable};
 use std::iter;
 
+use crate::liveness::{LiveNode, Variable};
+
 #[derive(Clone, Copy)]
 pub(super) struct RWU {
     pub(super) reader: bool,
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 2587a18b8c8..25115c5cafd 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,6 +1,5 @@
 use std::collections::BTreeMap;
 use std::fmt;
-use Context::*;
 
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
@@ -13,6 +12,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::{BytePos, Span};
+use Context::*;
 
 use crate::errors::{
     BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 2c34f477de5..4d58590ca3b 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -1,7 +1,9 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-use crate::errors;
+use std::mem::replace;
+use std::num::NonZero;
+
 use rustc_attr::{
     self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
     Unstable, UnstableReason, VERSION_PLACEHOLDER,
@@ -25,10 +27,10 @@ use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPR
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
-use std::mem::replace;
-use std::num::NonZero;
 use tracing::{debug, info};
 
+use crate::errors;
+
 #[derive(PartialEq)]
 enum AnnotationKind {
     /// Annotation is required if not inherited from unstable parents.
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index f3e8e547066..3a2a75a638f 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -180,16 +180,14 @@ use std::cmp::{self, max, min, Ordering};
 use std::fmt;
 use std::iter::once;
 
-use smallvec::SmallVec;
-
 use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS};
 use rustc_index::bit_set::{BitSet, GrowableBitSet};
 use rustc_index::IndexVec;
+use smallvec::SmallVec;
 
 use self::Constructor::*;
 use self::MaybeInfiniteInt::*;
 use self::SliceKind::*;
-
 use crate::PatCx;
 
 /// Whether we have seen a constructor in the column or not.
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 27f227e6d9c..1f7852e5190 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -1,6 +1,5 @@
 use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
-use rustc_middle::thir::Pat;
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
 
@@ -8,18 +7,18 @@ use crate::rustc::{RustcPatCtxt, WitnessPat};
 
 #[derive(Subdiagnostic)]
 #[label(pattern_analysis_uncovered)]
-pub struct Uncovered<'tcx> {
+pub struct Uncovered {
     #[primary_span]
     span: Span,
     count: usize,
-    witness_1: Pat<'tcx>,
-    witness_2: Pat<'tcx>,
-    witness_3: Pat<'tcx>,
+    witness_1: String, // a printed pattern
+    witness_2: String, // a printed pattern
+    witness_3: String, // a printed pattern
     remainder: usize,
 }
 
-impl<'tcx> Uncovered<'tcx> {
-    pub fn new<'p>(
+impl Uncovered {
+    pub fn new<'p, 'tcx>(
         span: Span,
         cx: &RustcPatCtxt<'p, 'tcx>,
         witnesses: Vec<WitnessPat<'p, 'tcx>>,
@@ -27,19 +26,13 @@ impl<'tcx> Uncovered<'tcx> {
     where
         'tcx: 'p,
     {
-        let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap());
+        let witness_1 = cx.print_witness_pat(witnesses.get(0).unwrap());
         Self {
             span,
             count: witnesses.len(),
             // Substitute dummy values if witnesses is smaller than 3. These will never be read.
-            witness_2: witnesses
-                .get(1)
-                .map(|w| cx.hoist_witness_pat(w))
-                .unwrap_or_else(|| witness_1.clone()),
-            witness_3: witnesses
-                .get(2)
-                .map(|w| cx.hoist_witness_pat(w))
-                .unwrap_or_else(|| witness_1.clone()),
+            witness_2: witnesses.get(1).map(|w| cx.print_witness_pat(w)).unwrap_or_default(),
+            witness_3: witnesses.get(2).map(|w| cx.print_witness_pat(w)).unwrap_or_default(),
             witness_1,
             remainder: witnesses.len().saturating_sub(3),
         }
@@ -49,19 +42,19 @@ impl<'tcx> Uncovered<'tcx> {
 #[derive(LintDiagnostic)]
 #[diag(pattern_analysis_overlapping_range_endpoints)]
 #[note]
-pub struct OverlappingRangeEndpoints<'tcx> {
+pub struct OverlappingRangeEndpoints {
     #[label]
     pub range: Span,
     #[subdiagnostic]
-    pub overlap: Vec<Overlap<'tcx>>,
+    pub overlap: Vec<Overlap>,
 }
 
-pub struct Overlap<'tcx> {
+pub struct Overlap {
     pub span: Span,
-    pub range: Pat<'tcx>,
+    pub range: String, // a printed pattern
 }
 
-impl<'tcx> Subdiagnostic for Overlap<'tcx> {
+impl Subdiagnostic for Overlap {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
@@ -78,38 +71,38 @@ impl<'tcx> Subdiagnostic for Overlap<'tcx> {
 
 #[derive(LintDiagnostic)]
 #[diag(pattern_analysis_excluside_range_missing_max)]
-pub struct ExclusiveRangeMissingMax<'tcx> {
+pub struct ExclusiveRangeMissingMax {
     #[label]
     #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")]
     /// This is an exclusive range that looks like `lo..max` (i.e. doesn't match `max`).
     pub first_range: Span,
     /// Suggest `lo..=max` instead.
     pub suggestion: String,
-    pub max: Pat<'tcx>,
+    pub max: String, // a printed pattern
 }
 
 #[derive(LintDiagnostic)]
 #[diag(pattern_analysis_excluside_range_missing_gap)]
-pub struct ExclusiveRangeMissingGap<'tcx> {
+pub struct ExclusiveRangeMissingGap {
     #[label]
     #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")]
     /// This is an exclusive range that looks like `lo..gap` (i.e. doesn't match `gap`).
     pub first_range: Span,
-    pub gap: Pat<'tcx>,
+    pub gap: String, // a printed pattern
     /// Suggest `lo..=gap` instead.
     pub suggestion: String,
     #[subdiagnostic]
     /// All these ranges skipped over `gap` which we think is probably a mistake.
-    pub gap_with: Vec<GappedRange<'tcx>>,
+    pub gap_with: Vec<GappedRange>,
 }
 
-pub struct GappedRange<'tcx> {
+pub struct GappedRange {
     pub span: Span,
-    pub gap: Pat<'tcx>,
-    pub first_range: Pat<'tcx>,
+    pub gap: String,         // a printed pattern
+    pub first_range: String, // a printed pattern
 }
 
-impl<'tcx> Subdiagnostic for GappedRange<'tcx> {
+impl Subdiagnostic for GappedRange {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
@@ -134,7 +127,7 @@ impl<'tcx> Subdiagnostic for GappedRange<'tcx> {
 pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
     pub scrut_ty: Ty<'tcx>,
     #[subdiagnostic]
-    pub uncovered: Uncovered<'tcx>,
+    pub uncovered: Uncovered,
 }
 
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index a5c0b13c90b..6c9c848bb10 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -5,6 +5,7 @@
 // tidy-alphabetical-start
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(feature = "rustc", feature(let_chains))]
 // tidy-alphabetical-end
 
 pub mod constructor;
@@ -54,7 +55,6 @@ pub trait PatCx: Sized + fmt::Debug {
     type PatData: Clone;
 
     fn is_exhaustive_patterns_feature_on(&self) -> bool;
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool;
 
     /// The number of fields for this constructor.
     fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize;
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index 892aacd7ac5..6bcef0ec879 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -1,11 +1,12 @@
+use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
+use rustc_span::ErrorGuaranteed;
+use tracing::instrument;
+
 use crate::constructor::Constructor;
 use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered};
 use crate::pat_column::PatternColumn;
 use crate::rustc::{RevealedTy, RustcPatCtxt, WitnessPat};
 use crate::MatchArm;
-use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
-use rustc_span::ErrorGuaranteed;
-use tracing::instrument;
 
 /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
 /// in a given column.
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index a591c3c554b..d91deab160c 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -5,11 +5,10 @@ use std::fmt;
 
 use smallvec::{smallvec, SmallVec};
 
+use self::Constructor::*;
 use crate::constructor::{Constructor, Slice, SliceKind};
 use crate::{PatCx, PrivateUninhabitedField};
 
-use self::Constructor::*;
-
 /// A globally unique id to distinguish patterns.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub(crate) struct PatId(u32);
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 910dd4c6c1a..10b7968a1a7 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -7,7 +7,7 @@ use rustc_hir::HirId;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::mir::{self, Const};
-use rustc_middle::thir::{self, FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
+use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
     self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
@@ -17,15 +17,17 @@ use rustc_session::lint;
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
 
+use crate::constructor::Constructor::*;
 use crate::constructor::{
     IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
 };
 use crate::lints::lint_nonexhaustive_missing_variants;
 use crate::pat_column::PatternColumn;
+use crate::rustc::print::EnumInfo;
 use crate::usefulness::{compute_match_usefulness, PlaceValidity};
 use crate::{errors, Captures, PatCx, PrivateUninhabitedField};
 
-use crate::constructor::Constructor::*;
+mod print;
 
 // Re-export rustc-specific versions of all these types.
 pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcPatCtxt<'p, 'tcx>>;
@@ -236,9 +238,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
                             let is_visible =
                                 adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
-                            let is_uninhabited = (cx.tcx.features().exhaustive_patterns
-                                || cx.tcx.features().min_exhaustive_patterns)
-                                && cx.is_uninhabited(*ty);
+                            let is_uninhabited = cx.is_uninhabited(*ty);
                             let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
                             (ty, PrivateUninhabitedField(skip))
                         });
@@ -744,7 +744,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     /// Note: it is possible to get `isize/usize::MAX+1` here, as explained in the doc for
     /// [`IntRange::split`]. This cannot be represented as a `Const`, so we represent it with
     /// `PosInfinity`.
-    pub(crate) fn hoist_pat_range_bdy(
+    fn hoist_pat_range_bdy(
         &self,
         miint: MaybeInfiniteInt,
         ty: RevealedTy<'tcx>,
@@ -774,8 +774,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         }
     }
 
-    /// Convert back to a `thir::Pat` for diagnostic purposes.
-    pub(crate) fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> {
+    /// Convert to a [`print::Pat`] for diagnostic purposes.
+    fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> print::Pat<'tcx> {
+        use print::{Pat, PatKind};
         use MaybeInfiniteInt::*;
         let cx = self;
         let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
@@ -809,83 +810,79 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() }))
         };
 
-        Pat { ty: ty.inner(), span: DUMMY_SP, kind }
+        Pat { ty: ty.inner(), kind }
     }
-    /// Convert back to a `thir::Pat` for diagnostic purposes. This panics for patterns that don't
+
+    /// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
+    pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
+        // This works by converting the witness pattern to a `print::Pat`
+        // and then printing that, but callers don't need to know that.
+        self.hoist_witness_pat(pat).to_string()
+    }
+
+    /// Convert to a [`print::Pat`] for diagnostic purposes. This panics for patterns that don't
     /// appear in diagnostics, like float ranges.
-    pub fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> Pat<'tcx> {
+    fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
+        use print::{FieldPat, Pat, PatKind};
         let cx = self;
-        let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
-        let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p)));
+        let hoist = |p| Box::new(cx.hoist_witness_pat(p));
         let kind = match pat.ctor() {
             Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
             IntRange(range) => return self.hoist_pat_range(range, *pat.ty()),
-            Struct | Variant(_) | UnionField => match pat.ty().kind() {
-                ty::Tuple(..) => PatKind::Leaf {
-                    subpatterns: subpatterns
-                        .enumerate()
-                        .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
-                        .collect(),
-                },
-                ty::Adt(adt_def, _) if adt_def.is_box() => {
-                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
-                    // of `std`). So this branch is only reachable when the feature is enabled and
-                    // the pattern is a box pattern.
-                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
-                }
-                ty::Adt(adt_def, args) => {
-                    let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), *adt_def);
-                    let subpatterns = subpatterns
-                        .enumerate()
-                        .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
-                        .collect();
+            Struct if pat.ty().is_box() => {
+                // Outside of the `alloc` crate, the only way to create a struct pattern
+                // of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
+                PatKind::Box { subpattern: hoist(&pat.fields[0]) }
+            }
+            Struct | Variant(_) | UnionField => {
+                let enum_info = match *pat.ty().kind() {
+                    ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
+                        adt_def,
+                        variant_index: RustcPatCtxt::variant_index_for_adt(pat.ctor(), adt_def),
+                    },
+                    ty::Adt(..) | ty::Tuple(..) => EnumInfo::NotEnum,
+                    _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()),
+                };
 
-                    if adt_def.is_enum() {
-                        PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns }
-                    } else {
-                        PatKind::Leaf { subpatterns }
-                    }
-                }
-                _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()),
-            },
-            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
-            // be careful to reconstruct the correct constant pattern here. However a string
-            // literal pattern will never be reported as a non-exhaustiveness witness, so we
-            // ignore this issue.
-            Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
+                let subpatterns = pat
+                    .iter_fields()
+                    .enumerate()
+                    .map(|(i, pat)| FieldPat { field: FieldIdx::new(i), pattern: hoist(pat) })
+                    .collect::<Vec<_>>();
+
+                PatKind::StructLike { enum_info, subpatterns }
+            }
+            Ref => PatKind::Deref { subpattern: hoist(&pat.fields[0]) },
             Slice(slice) => {
-                match slice.kind {
-                    SliceKind::FixedLen(_) => PatKind::Slice {
-                        prefix: subpatterns.collect(),
-                        slice: None,
-                        suffix: Box::new([]),
-                    },
-                    SliceKind::VarLen(prefix, _) => {
-                        let mut subpatterns = subpatterns.peekable();
-                        let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect();
-                        if slice.array_len.is_some() {
-                            // Improves diagnostics a bit: if the type is a known-size array, instead
-                            // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
-                            // This is incorrect if the size is not known, since `[_, ..]` captures
-                            // arrays of lengths `>= 1` whereas `[..]` captures any length.
-                            while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
-                                prefix.pop();
-                            }
-                            while subpatterns.peek().is_some()
-                                && is_wildcard(subpatterns.peek().unwrap())
-                            {
-                                subpatterns.next();
-                            }
-                        }
-                        let suffix: Box<[_]> = subpatterns.collect();
-                        let wild = Pat::wildcard_from_ty(pat.ty().inner());
-                        PatKind::Slice {
-                            prefix: prefix.into_boxed_slice(),
-                            slice: Some(Box::new(wild)),
-                            suffix,
-                        }
+                let (prefix_len, has_dot_dot) = match slice.kind {
+                    SliceKind::FixedLen(len) => (len, false),
+                    SliceKind::VarLen(prefix_len, _) => (prefix_len, true),
+                };
+
+                let (mut prefix, mut suffix) = pat.fields.split_at(prefix_len);
+
+                // If the pattern contains a `..`, but is applied to values of statically-known
+                // length (arrays), then we can slightly simplify diagnostics by merging any
+                // adjacent wildcard patterns into the `..`: `[x, _, .., _, y]` => `[x, .., y]`.
+                // (This simplification isn't allowed for slice values, because in that case
+                // `[x, .., y]` would match some slices that `[x, _, .., _, y]` would not.)
+                if has_dot_dot && slice.array_len.is_some() {
+                    while let [rest @ .., last] = prefix
+                        && would_print_as_wildcard(cx.tcx, last)
+                    {
+                        prefix = rest;
+                    }
+                    while let [first, rest @ ..] = suffix
+                        && would_print_as_wildcard(cx.tcx, first)
+                    {
+                        suffix = rest;
                     }
                 }
+
+                let prefix = prefix.iter().map(hoist).collect();
+                let suffix = suffix.iter().map(hoist).collect();
+
+                PatKind::Slice { prefix, has_dot_dot, suffix }
             }
             &Str(value) => PatKind::Constant { value },
             Never if self.tcx.features().never_patterns => PatKind::Never,
@@ -899,7 +896,23 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             }
         };
 
-        Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
+        Pat { ty: pat.ty().inner(), kind }
+    }
+}
+
+/// Returns `true` if the given pattern would be printed as a wildcard (`_`).
+fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool {
+    match p.ctor() {
+        Constructor::IntRange(IntRange {
+            lo: MaybeInfiniteInt::NegInfinity,
+            hi: MaybeInfiniteInt::PosInfinity,
+        })
+        | Constructor::Wildcard
+        | Constructor::NonExhaustive
+        | Constructor::Hidden
+        | Constructor::PrivateUninhabited => true,
+        Constructor::Never if !tcx.features().never_patterns => true,
+        _ => false,
     }
 }
 
@@ -914,9 +927,6 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
     fn is_exhaustive_patterns_feature_on(&self) -> bool {
         self.tcx.features().exhaustive_patterns
     }
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
-        self.tcx.features().min_exhaustive_patterns
-    }
 
     fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
         self.ctor_arity(ctor, *ty)
@@ -966,7 +976,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
         let overlaps: Vec<_> = overlaps_with
             .iter()
             .map(|pat| pat.data().span)
-            .map(|span| errors::Overlap { range: overlap_as_pat.clone(), span })
+            .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span })
             .collect();
         let pat_span = pat.data().span;
         self.tcx.emit_node_span_lint(
@@ -996,12 +1006,11 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
         }
         // `pat` is an exclusive range like `lo..gap`. `gapped_with` contains ranges that start with
         // `gap+1`.
-        let suggested_range: thir::Pat<'_> = {
+        let suggested_range: String = {
             // Suggest `lo..=gap` instead.
-            let mut suggested_range = thir_pat.clone();
-            let thir::PatKind::Range(range) = &mut suggested_range.kind else { unreachable!() };
-            range.end = rustc_hir::RangeEnd::Included;
-            suggested_range
+            let mut suggested_range = PatRange::clone(range);
+            suggested_range.end = rustc_hir::RangeEnd::Included;
+            suggested_range.to_string()
         };
         let gap_as_pat = self.hoist_pat_range(&gap, *pat.ty());
         if gapped_with.is_empty() {
@@ -1014,9 +1023,9 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
                     // Point at this range.
                     first_range: thir_pat.span,
                     // That's the gap that isn't covered.
-                    max: gap_as_pat.clone(),
+                    max: gap_as_pat.to_string(),
                     // Suggest `lo..=max` instead.
-                    suggestion: suggested_range.to_string(),
+                    suggestion: suggested_range,
                 },
             );
         } else {
@@ -1028,17 +1037,17 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
                     // Point at this range.
                     first_range: thir_pat.span,
                     // That's the gap that isn't covered.
-                    gap: gap_as_pat.clone(),
+                    gap: gap_as_pat.to_string(),
                     // Suggest `lo..=gap` instead.
-                    suggestion: suggested_range.to_string(),
+                    suggestion: suggested_range,
                     // All these ranges skipped over `gap` which we think is probably a
                     // mistake.
                     gap_with: gapped_with
                         .iter()
                         .map(|pat| errors::GappedRange {
                             span: pat.data().span,
-                            gap: gap_as_pat.clone(),
-                            first_range: thir_pat.clone(),
+                            gap: gap_as_pat.to_string(),
+                            first_range: range.to_string(),
                         })
                         .collect(),
                 },
diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs
new file mode 100644
index 00000000000..7d638714605
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs
@@ -0,0 +1,219 @@
+//! Pattern analysis sometimes wants to print patterns as part of a user-visible
+//! diagnostic.
+//!
+//! Historically it did so by creating a synthetic [`thir::Pat`](rustc_middle::thir::Pat)
+//! and printing that, but doing so was making it hard to modify the THIR pattern
+//! representation for other purposes.
+//!
+//! So this module contains a forked copy of `thir::Pat` that is used _only_
+//! for diagnostics, and has been partly simplified to remove things that aren't
+//! needed for printing.
+
+use std::fmt;
+
+use rustc_middle::thir::PatRange;
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::{bug, mir};
+use rustc_span::sym;
+use rustc_target::abi::{FieldIdx, VariantIdx};
+
+#[derive(Clone, Debug)]
+pub(crate) struct FieldPat<'tcx> {
+    pub(crate) field: FieldIdx,
+    pub(crate) pattern: Box<Pat<'tcx>>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct Pat<'tcx> {
+    pub(crate) ty: Ty<'tcx>,
+    pub(crate) kind: PatKind<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum PatKind<'tcx> {
+    Wild,
+
+    StructLike {
+        enum_info: EnumInfo<'tcx>,
+        subpatterns: Vec<FieldPat<'tcx>>,
+    },
+
+    Box {
+        subpattern: Box<Pat<'tcx>>,
+    },
+
+    Deref {
+        subpattern: Box<Pat<'tcx>>,
+    },
+
+    Constant {
+        value: mir::Const<'tcx>,
+    },
+
+    Range(Box<PatRange<'tcx>>),
+
+    Slice {
+        prefix: Box<[Box<Pat<'tcx>>]>,
+        /// True if this slice-like pattern should include a `..` between the
+        /// prefix and suffix.
+        has_dot_dot: bool,
+        suffix: Box<[Box<Pat<'tcx>>]>,
+    },
+
+    Never,
+}
+
+impl<'tcx> fmt::Display for Pat<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.kind {
+            PatKind::Wild => write!(f, "_"),
+            PatKind::Never => write!(f, "!"),
+            PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"),
+            PatKind::StructLike { ref enum_info, ref subpatterns } => {
+                ty::tls::with(|tcx| write_struct_like(f, tcx, self.ty, enum_info, subpatterns))
+            }
+            PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
+            PatKind::Constant { value } => write!(f, "{value}"),
+            PatKind::Range(ref range) => write!(f, "{range}"),
+            PatKind::Slice { ref prefix, has_dot_dot, ref suffix } => {
+                write_slice_like(f, prefix, has_dot_dot, suffix)
+            }
+        }
+    }
+}
+
+/// Returns a closure that will return `""` when called the first time,
+/// and then return `", "` when called any subsequent times.
+/// Useful for printing comma-separated lists.
+fn start_or_comma() -> impl FnMut() -> &'static str {
+    let mut first = true;
+    move || {
+        if first {
+            first = false;
+            ""
+        } else {
+            ", "
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum EnumInfo<'tcx> {
+    Enum { adt_def: AdtDef<'tcx>, variant_index: VariantIdx },
+    NotEnum,
+}
+
+fn write_struct_like<'tcx>(
+    f: &mut impl fmt::Write,
+    tcx: TyCtxt<'_>,
+    ty: Ty<'tcx>,
+    enum_info: &EnumInfo<'tcx>,
+    subpatterns: &[FieldPat<'tcx>],
+) -> fmt::Result {
+    let variant_and_name = match *enum_info {
+        EnumInfo::Enum { adt_def, variant_index } => {
+            let variant = adt_def.variant(variant_index);
+            let adt_did = adt_def.did();
+            let name = if tcx.is_diagnostic_item(sym::Option, adt_did)
+                || tcx.is_diagnostic_item(sym::Result, adt_did)
+            {
+                variant.name.to_string()
+            } else {
+                format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
+            };
+            Some((variant, name))
+        }
+        EnumInfo::NotEnum => ty.ty_adt_def().and_then(|adt_def| {
+            Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
+        }),
+    };
+
+    let mut start_or_comma = start_or_comma();
+
+    if let Some((variant, name)) = &variant_and_name {
+        write!(f, "{name}")?;
+
+        // Only for Adt we can have `S {...}`,
+        // which we handle separately here.
+        if variant.ctor.is_none() {
+            write!(f, " {{ ")?;
+
+            let mut printed = 0;
+            for p in subpatterns {
+                if let PatKind::Wild = p.pattern.kind {
+                    continue;
+                }
+                let name = variant.fields[p.field].name;
+                write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+                printed += 1;
+            }
+
+            let is_union = ty.ty_adt_def().is_some_and(|adt| adt.is_union());
+            if printed < variant.fields.len() && (!is_union || printed == 0) {
+                write!(f, "{}..", start_or_comma())?;
+            }
+
+            return write!(f, " }}");
+        }
+    }
+
+    let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
+    if num_fields != 0 || variant_and_name.is_none() {
+        write!(f, "(")?;
+        for i in 0..num_fields {
+            write!(f, "{}", start_or_comma())?;
+
+            // Common case: the field is where we expect it.
+            if let Some(p) = subpatterns.get(i) {
+                if p.field.index() == i {
+                    write!(f, "{}", p.pattern)?;
+                    continue;
+                }
+            }
+
+            // Otherwise, we have to go looking for it.
+            if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+                write!(f, "{}", p.pattern)?;
+            } else {
+                write!(f, "_")?;
+            }
+        }
+        write!(f, ")")?;
+    }
+
+    Ok(())
+}
+
+fn write_ref_like<'tcx>(
+    f: &mut impl fmt::Write,
+    ty: Ty<'tcx>,
+    subpattern: &Pat<'tcx>,
+) -> fmt::Result {
+    match ty.kind() {
+        ty::Ref(_, _, mutbl) => {
+            write!(f, "&{}", mutbl.prefix_str())?;
+        }
+        _ => bug!("{ty} is a bad ref pattern type"),
+    }
+    write!(f, "{subpattern}")
+}
+
+fn write_slice_like<'tcx>(
+    f: &mut impl fmt::Write,
+    prefix: &[Box<Pat<'tcx>>],
+    has_dot_dot: bool,
+    suffix: &[Box<Pat<'tcx>>],
+) -> fmt::Result {
+    let mut start_or_comma = start_or_comma();
+    write!(f, "[")?;
+    for p in prefix.iter() {
+        write!(f, "{}{}", start_or_comma(), p)?;
+    }
+    if has_dot_dot {
+        write!(f, "{}..", start_or_comma())?;
+    }
+    for p in suffix.iter() {
+        write!(f, "{}{}", start_or_comma(), p)?;
+    }
+    write!(f, "]")
+}
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 76dc338e71c..6535afcc398 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -543,13 +543,11 @@
 //! recurse into subpatterns. That second part is done through [`PlaceValidity`], most notably
 //! [`PlaceValidity::specialize`].
 //!
-//! Having said all that, in practice we don't fully follow what's been presented in this section.
-//! Let's call "toplevel exception" the case where the match scrutinee itself has type `!` or
-//! `EmptyEnum`. First, on stable rust, we require `_` patterns for empty types in all cases apart
-//! from the toplevel exception. The `exhaustive_patterns` and `min_exaustive_patterns` allow
-//! omitting patterns in the cases described above. There's a final detail: in the toplevel
-//! exception or with the `exhaustive_patterns` feature, we ignore place validity when checking
-//! whether a pattern is required for exhaustiveness. I (Nadrieril) hope to deprecate this behavior.
+//! Having said all that, we don't fully follow what's been presented in this section. For
+//! backwards-compatibility, we ignore place validity when checking whether a pattern is required
+//! for exhaustiveness in two cases: when the `exhaustive_patterns` feature gate is on, or when the
+//! match scrutinee itself has type `!` or `EmptyEnum`. I (Nadrieril) hope to deprecate this
+//! exception.
 //!
 //!
 //!
@@ -709,18 +707,19 @@
 //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
 //! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
 
-use self::PlaceValidity::*;
-use crate::constructor::{Constructor, ConstructorSet, IntRange};
-use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat};
-use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField};
+use std::fmt;
+
+#[cfg(feature = "rustc")]
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hash::{FxHashMap, FxHashSet};
 use rustc_index::bit_set::BitSet;
 use smallvec::{smallvec, SmallVec};
-use std::fmt;
 use tracing::{debug, instrument};
 
-#[cfg(feature = "rustc")]
-use rustc_data_structures::stack::ensure_sufficient_stack;
+use self::PlaceValidity::*;
+use crate::constructor::{Constructor, ConstructorSet, IntRange};
+use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat};
+use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField};
 #[cfg(not(feature = "rustc"))]
 pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
     f()
@@ -952,13 +951,10 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
             self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
         // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
         // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
-        let empty_arms_are_unreachable = self.validity.is_known_valid()
-            && (is_toplevel_exception
-                || cx.is_exhaustive_patterns_feature_on()
-                || cx.is_min_exhaustive_patterns_feature_on());
+        let empty_arms_are_unreachable = self.validity.is_known_valid();
         // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
         // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
-        let can_omit_empty_arms = empty_arms_are_unreachable
+        let can_omit_empty_arms = self.validity.is_known_valid()
             || is_toplevel_exception
             || cx.is_exhaustive_patterns_feature_on();
 
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
index 68ec75b7705..ec0bcd43ad2 100644
--- a/compiler/rustc_pattern_analysis/tests/common/mod.rs
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -1,10 +1,8 @@
-use rustc_pattern_analysis::{
-    constructor::{
-        Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
-    },
-    usefulness::{PlaceValidity, UsefulnessReport},
-    Captures, MatchArm, PatCx, PrivateUninhabitedField,
+use rustc_pattern_analysis::constructor::{
+    Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
 };
+use rustc_pattern_analysis::usefulness::{PlaceValidity, UsefulnessReport};
+use rustc_pattern_analysis::{Captures, MatchArm, PatCx, PrivateUninhabitedField};
 
 /// Sets up `tracing` for easier debugging. Tries to look like the `rustc` setup.
 pub fn init_tracing() {
@@ -154,10 +152,6 @@ impl PatCx for Cx {
         false
     }
 
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
-        true
-    }
-
     fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize {
         ty.sub_tys(ctor).len()
     }
diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs
index 19242d44e35..3a9b9e9f075 100644
--- a/compiler/rustc_pattern_analysis/tests/complexity.rs
+++ b/compiler/rustc_pattern_analysis/tests/complexity.rs
@@ -1,7 +1,9 @@
 //! Test the pattern complexity limit.
 
 use common::*;
-use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm};
+use rustc_pattern_analysis::pat::DeconstructedPat;
+use rustc_pattern_analysis::usefulness::PlaceValidity;
+use rustc_pattern_analysis::MatchArm;
 
 #[macro_use]
 mod common;
diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
index 205d430d495..2192940d4d7 100644
--- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
+++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
@@ -1,11 +1,9 @@
 //! Test exhaustiveness checking.
 
 use common::*;
-use rustc_pattern_analysis::{
-    pat::{DeconstructedPat, WitnessPat},
-    usefulness::PlaceValidity,
-    MatchArm,
-};
+use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
+use rustc_pattern_analysis::usefulness::PlaceValidity;
+use rustc_pattern_analysis::MatchArm;
 
 #[macro_use]
 mod common;
diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs
index 8c8cb3c796d..1c26e179f2e 100644
--- a/compiler/rustc_pattern_analysis/tests/intersection.rs
+++ b/compiler/rustc_pattern_analysis/tests/intersection.rs
@@ -1,7 +1,9 @@
 //! Test the computation of arm intersections.
 
 use common::*;
-use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm};
+use rustc_pattern_analysis::pat::DeconstructedPat;
+use rustc_pattern_analysis::usefulness::PlaceValidity;
+use rustc_pattern_analysis::MatchArm;
 
 #[macro_use]
 mod common;
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index ee04c335f2b..89face10750 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -1,4 +1,5 @@
-use rustc_errors::{codes::*, DiagArgFromDisplay};
+use rustc_errors::codes::*;
+use rustc_errors::DiagArgFromDisplay;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index d3705626938..d1d1e5e901f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -10,12 +10,19 @@
 
 mod errors;
 
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::ControlFlow;
+
+use errors::{
+    FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
+    ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint,
+    UnnamedItemIsPrivate,
+};
 use rustc_ast::visit::{try_visit, VisitorResult};
 use rustc_ast::MacroDef;
-use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
@@ -23,25 +30,17 @@ use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, Const, GenericParamDefKind};
-use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{
+    self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitable, TypeVisitor,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use tracing::debug;
-
-use std::fmt;
-use std::marker::PhantomData;
-use std::ops::ControlFlow;
-
-use errors::{
-    FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
-    ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint,
-    UnnamedItemIsPrivate,
-};
+use {rustc_attr as attr, rustc_hir as hir};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 825c1e2e9bc..18f97d6fb8f 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -10,20 +10,17 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
-use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
-use crate::profiling_support::QueryKeyStringCache;
 use field_offset::offset_of;
 use rustc_data_structures::stable_hasher::HashStable;
 use rustc_data_structures::sync::AtomicU64;
 use rustc_middle::arena::Arena;
-use rustc_middle::dep_graph::DepNodeIndex;
-use rustc_middle::dep_graph::{self, DepKind, DepKindStruct};
+use rustc_middle::dep_graph::{self, DepKind, DepKindStruct, DepNodeIndex};
 use rustc_middle::query::erase::{erase, restore, Erase};
 use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
 use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns};
-use rustc_middle::query::AsLocalKey;
 use rustc_middle::query::{
-    queries, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
+    queries, AsLocalKey, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine,
+    QueryStates,
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_query_system::dep_graph::SerializedDepNodeIndex;
@@ -32,10 +29,12 @@ use rustc_query_system::query::{
     get_query_incr, get_query_non_incr, CycleError, HashResult, QueryCache, QueryConfig, QueryMap,
     QueryMode, QueryState,
 };
-use rustc_query_system::HandleCycleError;
-use rustc_query_system::Value;
+use rustc_query_system::{HandleCycleError, Value};
 use rustc_span::{ErrorGuaranteed, Span};
 
+use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
+use crate::profiling_support::QueryKeyStringCache;
+
 #[macro_use]
 mod plumbing;
 pub use crate::plumbing::{query_key_hash_verify_all, QueryCtxt};
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 62e39377214..b9e700c1938 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -2,19 +2,21 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::QueryConfigRestored;
+use std::num::NonZero;
+
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::DiagInner;
 use rustc_index::Idx;
 use rustc_middle::bug;
-use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::dep_graph::{
-    self, DepContext, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
+    self, dep_kinds, DepContext, DepKind, DepKindStruct, DepNode, DepNodeIndex,
+    SerializedDepNodeIndex,
+};
+use rustc_middle::query::on_disk_cache::{
+    AbsoluteBytePos, CacheDecoder, CacheEncoder, EncodedDepNodeIndex,
 };
-use rustc_middle::query::on_disk_cache::AbsoluteBytePos;
-use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
 use rustc_middle::query::Key;
 use rustc_middle::ty::print::with_reduced_queries;
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
@@ -26,13 +28,13 @@ use rustc_query_system::query::{
     QueryStackFrame,
 };
 use rustc_query_system::{LayoutOfDepth, QueryOverflow};
-use rustc_serialize::Decodable;
-use rustc_serialize::Encodable;
+use rustc_serialize::{Decodable, Encodable};
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
-use std::num::NonZero;
 use thin_vec::ThinVec;
 
+use crate::QueryConfigRestored;
+
 #[derive(Copy, Clone)]
 pub struct QueryCtxt<'tcx> {
     pub tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index e0d7a4f0451..599316d0cad 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -1,3 +1,6 @@
+use std::fmt::Debug;
+use std::io::Write;
+
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
@@ -5,8 +8,6 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_middle::ty::TyCtxt;
 use rustc_query_system::query::QueryCache;
-use std::fmt::Debug;
-use std::io::Write;
 
 pub(crate) struct QueryKeyStringCache {
     def_id_cache: FxHashMap<DefId, StringId>,
diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs
index d8a5bdba7b8..1b8332ad9e0 100644
--- a/compiler/rustc_query_system/src/cache.rs
+++ b/compiler/rustc_query_system/src/cache.rs
@@ -1,11 +1,11 @@
 //! Cache for candidate selection.
 
-use crate::dep_graph::{DepContext, DepNodeIndex};
+use std::hash::Hash;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 
-use std::hash::Hash;
+use crate::dep_graph::{DepContext, DepNodeIndex};
 
 pub struct Cache<Key, Value> {
     hashmap: Lock<FxHashMap<Key, WithDepNode<Value>>>,
diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs
index 103a6c01bd2..12ed5742711 100644
--- a/compiler/rustc_query_system/src/dep_graph/debug.rs
+++ b/compiler/rustc_query_system/src/dep_graph/debug.rs
@@ -1,9 +1,11 @@
 //! Code for debugging the dep-graph.
 
-use super::{DepNode, DepNodeIndex};
+use std::error::Error;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
-use std::error::Error;
+
+use super::{DepNode, DepNodeIndex};
 
 /// A dep-node filter goes from a user-defined string to a query over
 /// nodes. Right now the format is like this:
@@ -44,15 +46,14 @@ pub struct EdgeFilter {
 
 impl EdgeFilter {
     pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> {
-        let parts: Vec<_> = test.split("->").collect();
-        if parts.len() != 2 {
-            Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
-        } else {
+        if let [source, target] = *test.split("->").collect::<Vec<_>>() {
             Ok(EdgeFilter {
-                source: DepNodeFilter::new(parts[0]),
-                target: DepNodeFilter::new(parts[1]),
+                source: DepNodeFilter::new(source),
+                target: DepNodeFilter::new(target),
                 index_to_node: Lock::new(FxHashMap::default()),
             })
+        } else {
+            Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
         }
     }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index f2a68e35671..dfd0527252d 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -42,16 +42,17 @@
 //!   `DefId` it was computed from. In other cases, too much information gets
 //!   lost during fingerprint computation.
 
-use super::{DepContext, FingerprintStyle};
-use crate::ich::StableHashingContext;
+use std::fmt;
+use std::hash::Hash;
 
 use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_data_structures::AtomicRef;
 use rustc_hir::definitions::DefPathHash;
 use rustc_macros::{Decodable, Encodable};
-use std::fmt;
-use std::hash::Hash;
+
+use super::{DepContext, FingerprintStyle};
+use crate::ich::StableHashingContext;
 
 /// This serves as an index into arrays built by `make_dep_kind_array`.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
@@ -312,8 +313,9 @@ impl StableOrd for WorkProductId {
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(DepKind, 2);
     #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
diff --git a/compiler/rustc_query_system/src/dep_graph/edges.rs b/compiler/rustc_query_system/src/dep_graph/edges.rs
index 63d46f47f5c..9a3763bd4ee 100644
--- a/compiler/rustc_query_system/src/dep_graph/edges.rs
+++ b/compiler/rustc_query_system/src/dep_graph/edges.rs
@@ -1,8 +1,10 @@
-use crate::dep_graph::DepNodeIndex;
-use smallvec::SmallVec;
 use std::hash::{Hash, Hasher};
 use std::ops::Deref;
 
+use smallvec::SmallVec;
+
+use crate::dep_graph::DepNodeIndex;
+
 #[derive(Default, Debug)]
 pub(crate) struct EdgesVec {
     max: u32,
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 66fb3136805..b6aa1d5a43b 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1,3 +1,11 @@
+use std::assert_matches::assert_matches;
+use std::collections::hash_map::Entry;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::marker::PhantomData;
+use std::sync::atomic::Ordering;
+use std::sync::Arc;
+
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef};
@@ -8,14 +16,9 @@ use rustc_data_structures::unord::UnordMap;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-use std::assert_matches::assert_matches;
-use std::collections::hash_map::Entry;
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::marker::PhantomData;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
 use tracing::{debug, instrument};
+#[cfg(debug_assertions)]
+use {super::debug::EdgeFilter, std::env};
 
 use super::query::DepGraphQuery;
 use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
@@ -24,9 +27,6 @@ use crate::dep_graph::edges::EdgesVec;
 use crate::ich::StableHashingContext;
 use crate::query::{QueryContext, QuerySideEffects};
 
-#[cfg(debug_assertions)]
-use {super::debug::EdgeFilter, std::env};
-
 #[derive(Clone)]
 pub struct DepGraph<D: Deps> {
     data: Option<Lrc<DepGraphData<D>>>,
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index cfb25ec905f..291f275ef3c 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -5,18 +5,19 @@ mod graph;
 mod query;
 mod serialized;
 
+use std::panic;
+
 pub use dep_node::{DepKind, DepKindStruct, DepNode, DepNodeParams, WorkProductId};
 pub(crate) use graph::DepGraphData;
 pub use graph::{hash_result, DepGraph, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap};
 pub use query::DepGraphQuery;
+use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_session::Session;
 pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+use tracing::instrument;
 
 use self::graph::{print_markframe_trace, MarkFrame};
 use crate::ich::StableHashingContext;
-use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_session::Session;
-use std::panic;
-use tracing::instrument;
 
 pub trait DepContext: Copy {
     type Deps: Deps;
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 8e91d9dd60b..ff1c3431b7c 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -35,11 +35,11 @@
 //! If the number of edges in this node does not fit in the bits available in the header, we
 //! store it directly after the header with leb128.
 
-use super::query::DepGraphQuery;
-use super::{DepKind, DepNode, DepNodeIndex, Deps};
-use crate::dep_graph::edges::EdgesVec;
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fingerprint::PackedFingerprint;
+use std::iter;
+use std::marker::PhantomData;
+use std::sync::Arc;
+
+use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::outline;
 use rustc_data_structures::profiling::SelfProfilerRef;
@@ -48,11 +48,12 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_index::{Idx, IndexVec};
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::iter;
-use std::marker::PhantomData;
-use std::sync::Arc;
 use tracing::{debug, instrument};
 
+use super::query::DepGraphQuery;
+use super::{DepKind, DepNode, DepNodeIndex, Deps};
+use crate::dep_graph::edges::EdgesVec;
+
 // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
 // unused so that we can store multiple index types in `CompressedHybridIndex`,
 // and use those bits to encode which index type it contains.
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index e7eb9694f47..756ad3b1a2d 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -1,5 +1,3 @@
-use crate::ich;
-
 use rustc_ast as ast;
 use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
 use rustc_data_structures::sync::Lrc;
@@ -11,6 +9,8 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData, DUMMY_SP};
 
+use crate::ich;
+
 /// This is the context state available during incr. comp. hashing. It contains
 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 39da5e395c4..8d7a6e4fa9b 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -1,15 +1,15 @@
 //! This module contains `HashStable` implementations for various data types
 //! from `rustc_ast` in no particular order.
 
-use crate::ich::StableHashingContext;
+use std::assert_matches::assert_matches;
 
 use rustc_ast as ast;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_span::SourceFile;
-use std::assert_matches::assert_matches;
-
 use smallvec::SmallVec;
 
+use crate::ich::StableHashingContext;
+
 impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}
 
 impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs
index 86e3ecb1edd..bae76885141 100644
--- a/compiler/rustc_query_system/src/ich/mod.rs
+++ b/compiler/rustc_query_system/src/ich/mod.rs
@@ -1,8 +1,9 @@
 //! ICH - Incremental Compilation Hash
 
-pub use self::hcx::StableHashingContext;
 use rustc_span::symbol::{sym, Symbol};
 
+pub use self::hcx::StableHashingContext;
+
 mod hcx;
 mod impls_syntax;
 
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 41222e83f7c..7a50a9534c2 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -14,9 +14,7 @@ pub mod ich;
 pub mod query;
 mod values;
 
-pub use error::HandleCycleError;
-pub use error::LayoutOfDepth;
-pub use error::QueryOverflow;
+pub use error::{HandleCycleError, LayoutOfDepth, QueryOverflow};
 pub use values::Value;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index acc29b67ccc..a4ced3d2c24 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -1,14 +1,14 @@
-use crate::dep_graph::DepNodeIndex;
+use std::fmt::Debug;
+use std::hash::Hash;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sharded::{self, Sharded};
 use rustc_data_structures::sync::{Lock, OnceLock};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_index::{Idx, IndexVec};
-use rustc_span::def_id::DefId;
-use rustc_span::def_id::DefIndex;
-use std::fmt::Debug;
-use std::hash::Hash;
+use rustc_span::def_id::{DefId, DefIndex};
+
+use crate::dep_graph::DepNodeIndex;
 
 pub trait QueryCache: Sized {
     type Key: Hash + Eq + Copy + Debug;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 958d9fdb52a..371b896400a 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -1,16 +1,16 @@
 //! Query configuration and description traits.
 
+use std::fmt::Debug;
+use std::hash::Hash;
+
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_span::ErrorGuaranteed;
+
 use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex};
 use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
-use crate::query::DepNodeIndex;
-use crate::query::{CycleError, QueryContext, QueryState};
-
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_span::ErrorGuaranteed;
-use std::fmt::Debug;
-use std::hash::Hash;
+use crate::query::{CycleError, DepNodeIndex, QueryContext, QueryState};
 
 pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
 
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 3f44b11850e..ca3efc11201 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,18 +1,12 @@
-use crate::dep_graph::DepContext;
-use crate::error::CycleStack;
-use crate::query::plumbing::CycleError;
-use crate::query::DepKind;
-use crate::query::{QueryContext, QueryStackFrame};
+use std::hash::Hash;
+use std::io::Write;
+use std::num::NonZero;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Diag, DiagCtxtHandle};
 use rustc_hir::def::DefKind;
 use rustc_session::Session;
 use rustc_span::Span;
-
-use std::hash::Hash;
-use std::io::Write;
-use std::num::NonZero;
-
 #[cfg(parallel_compiler)]
 use {
     parking_lot::{Condvar, Mutex},
@@ -23,6 +17,11 @@ use {
     std::sync::Arc,
 };
 
+use crate::dep_graph::DepContext;
+use crate::error::CycleStack;
+use crate::query::plumbing::CycleError;
+use crate::query::{DepKind, QueryContext, QueryStackFrame};
+
 /// Represents a span and a query key.
 #[derive(Clone, Debug)]
 pub struct QueryInfo {
@@ -589,7 +588,7 @@ pub fn report_cycle<'a>(
         cycle_stack,
         stack_bottom: stack[0].query.description.to_owned(),
         alias,
-        cycle_usage: cycle_usage,
+        cycle_usage,
         stack_count,
         note_span: (),
     };
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index ab4f48fcd32..db00c265159 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -12,10 +12,6 @@ mod caches;
 pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
 
 mod config;
-pub use self::config::{HashResult, QueryConfig};
-
-use crate::dep_graph::DepKind;
-use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
 use rustc_data_structures::stable_hasher::Hash64;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::DiagInner;
@@ -25,6 +21,9 @@ use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use thin_vec::ThinVec;
 
+pub use self::config::{HashResult, QueryConfig};
+use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
+
 /// Description of a frame in the query stack.
 ///
 /// This is mostly used in case of cycles for error reporting.
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index d37d5bce9cc..8ef680cdb6c 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -2,16 +2,12 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::DepGraphData;
-use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
-use crate::ich::StableHashingContext;
-use crate::query::caches::QueryCache;
-#[cfg(parallel_compiler)]
-use crate::query::job::QueryLatch;
-use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
-use crate::query::SerializedDepNodeIndex;
-use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
-use crate::HandleCycleError;
+use std::cell::Cell;
+use std::collections::hash_map::Entry;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::mem;
+
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sharded::Sharded;
@@ -21,15 +17,20 @@ use rustc_data_structures::sync::Lock;
 use rustc_data_structures::{outline, sync};
 use rustc_errors::{Diag, FatalError, StashKey};
 use rustc_span::{Span, DUMMY_SP};
-use std::cell::Cell;
-use std::collections::hash_map::Entry;
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::mem;
 use thin_vec::ThinVec;
 use tracing::instrument;
 
 use super::QueryConfig;
+use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams};
+use crate::ich::StableHashingContext;
+use crate::query::caches::QueryCache;
+#[cfg(parallel_compiler)]
+use crate::query::job::QueryLatch;
+use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
+use crate::query::{
+    QueryContext, QueryMap, QuerySideEffects, QueryStackFrame, SerializedDepNodeIndex,
+};
+use crate::HandleCycleError;
 
 pub struct QueryState<K> {
     active: Sharded<FxHashMap<K, QueryResult>>,
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index ced5ac17dac..d57dabdd78d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -5,18 +5,13 @@
 //! unexpanded macros in the fragment are visited and registered.
 //! Imports are also considered items and placed into modules here, but not resolved yet.
 
-use crate::def_collector::collect_definitions;
-use crate::imports::{ImportData, ImportKind};
-use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
-use crate::Namespace::{MacroNS, TypeNS, ValueNS};
-use crate::{errors, BindingKey, MacroData, NameBindingData};
-use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
-use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};
+use std::cell::Cell;
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
-use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
-use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
+use rustc_ast::{
+    self as ast, AssocItem, AssocItemKind, Block, ForeignItem, ForeignItemKind, Impl, Item,
+    ItemKind, MetaItemKind, NodeId, StmtKind,
+};
 use rustc_attr as attr;
 use rustc_data_structures::sync::Lrc;
 use rustc_expand::base::ResolverExpand;
@@ -30,11 +25,18 @@ use rustc_middle::{bug, ty};
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
-
-use std::cell::Cell;
-
 use tracing::debug;
 
+use crate::def_collector::collect_definitions;
+use crate::imports::{ImportData, ImportKind};
+use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
+use crate::Namespace::{MacroNS, TypeNS, ValueNS};
+use crate::{
+    errors, BindingKey, Determinacy, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind,
+    ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult,
+    ResolutionError, Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError,
+};
+
 type Res = def::Res<NodeId>;
 
 impl<'a, Id: Into<DefId>> ToNameBinding<'a>
@@ -281,6 +283,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     parent_scope,
                     finalize.then(|| Finalize::new(id, path.span)),
                     None,
+                    None,
                 ) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         let res = module.res().expect("visibility resolved to unnamed block");
@@ -370,8 +373,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             has_attributes: !item.attrs.is_empty(),
             root_span,
             root_id,
-            vis: Cell::new(Some(vis)),
-            used: Default::default(),
+            vis,
         });
 
         self.r.indeterminate_imports.push(import);
@@ -886,9 +888,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             root_span: item.span,
             span: item.span,
             module_path: Vec::new(),
-            vis: Cell::new(Some(vis)),
-            used: Cell::new(used.then_some(Used::Other)),
+            vis,
         });
+        if used {
+            self.r.import_use_map.insert(import, Used::Other);
+        }
         self.r.potentially_unused_imports.push(import);
         let imported_binding = self.r.import(binding, import);
         if parent == self.r.graph_root {
@@ -1087,8 +1091,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
-                used: Default::default(),
+                vis: ty::Visibility::Restricted(CRATE_DEF_ID),
             })
         };
 
@@ -1123,6 +1126,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     ident,
                     MacroNS,
                     &self.parent_scope,
+                    None,
                 );
                 if let Ok(binding) = result {
                     let import = macro_use_import(self, ident.span, false);
@@ -1251,9 +1255,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     root_span: span,
                     span,
                     module_path: Vec::new(),
-                    vis: Cell::new(Some(vis)),
-                    used: Cell::new(Some(Used::Other)),
+                    vis,
                 });
+                self.r.import_use_map.insert(import, Used::Other);
                 let import_binding = self.r.import(binding, import);
                 self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
             } else {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index fc3669fecc2..1cee876b80f 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -23,23 +23,22 @@
 //  - `check_unused` finally emits the diagnostics based on the data generated
 //    in the last step
 
-use crate::imports::{Import, ImportKind};
-use crate::module_to_string;
-use crate::Resolver;
-
-use crate::{LexicalScopeBinding, NameBindingKind};
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
-use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES};
-use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS};
+use rustc_session::lint::builtin::{
+    MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS,
+};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, DUMMY_SP};
 
+use crate::imports::{Import, ImportKind};
+use crate::{module_to_string, LexicalScopeBinding, NameBindingKind, Resolver};
+
 struct UnusedImport {
     use_tree: ast::UseTree,
     use_tree_id: ast::NodeId,
@@ -382,9 +381,9 @@ impl Resolver<'_, '_> {
 
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
-                _ if import.used.get().is_some()
-                    || import.expect_vis().is_public()
-                    || import.span.is_dummy() =>
+                _ if import.vis.is_public()
+                    || import.span.is_dummy()
+                    || self.import_use_map.contains_key(import) =>
                 {
                     if let ImportKind::MacroUse { .. } = import.kind {
                         if !import.span.is_dummy() {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 1fb942de734..ed23870dfdf 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -1,4 +1,5 @@
-use crate::{ImplTraitContext, Resolver};
+use std::mem;
+
 use rustc_ast::visit::FnKind;
 use rustc_ast::*;
 use rustc_expand::expand::AstFragment;
@@ -8,9 +9,10 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-use std::mem;
 use tracing::debug;
 
+use crate::{ImplTraitContext, Resolver};
+
 pub(crate) fn collect_definitions(
     resolver: &mut Resolver<'_, '_>,
     fragment: &AstFragment,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index df80f4df5b9..942026ef012 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1,12 +1,15 @@
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID};
-use rustc_ast::{MetaItemKind, NestedMetaItem};
+use rustc_ast::{
+    self as ast, Crate, ItemKind, MetaItemKind, ModKind, NestedMetaItem, NodeId, Path,
+    CRATE_NODE_ID,
+};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxtHandle,
+    report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxtHandle,
     ErrorGuaranteed, MultiSpan, SuggestionStyle,
 };
 use rustc_feature::BUILTIN_ATTRIBUTES;
@@ -16,9 +19,10 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
-use rustc_session::lint::builtin::AMBIGUOUS_GLOB_IMPORTS;
-use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
+use rustc_session::lint::builtin::{
+    ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS,
+    MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+};
 use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag};
 use rustc_session::Session;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -36,13 +40,13 @@ use crate::errors::{
 };
 use crate::imports::{Import, ImportKind};
 use crate::late::{PatternSource, Rib};
-use crate::{errors as errs, BindingKey};
-use crate::{path_names_to_string, Used};
-use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
-use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
-use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
-use crate::{Segment, UseError};
+use crate::{
+    errors as errs, path_names_to_string, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind,
+    BindingError, BindingKey, Finalize, HasGenericParams, LexicalScopeBinding, MacroRulesScope,
+    Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
+    PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
+    VisResolutionError,
+};
 
 type Res = def::Res<ast::NodeId>;
 
@@ -1048,6 +1052,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 parent_scope,
                                 false,
                                 false,
+                                None,
                             ) {
                                 suggestions.extend(
                                     ext.helper_attrs
@@ -1502,6 +1507,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 false,
                 None,
+                None,
             ) {
                 let desc = match binding.res() {
                     Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
@@ -1979,6 +1985,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
         module: Option<ModuleOrUniformRoot<'a>>,
         failed_segment_idx: usize,
         ident: Ident,
@@ -2022,14 +2029,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         Applicability::MaybeIncorrect,
                     )),
                 )
+            } else if ident.name == kw::Underscore {
+                (format!("`_` is not a valid crate or module name"), None)
             } else if self.tcx.sess.is_rust_2015() {
                 (
                     format!("you might be missing crate `{ident}`"),
                     Some((
-                        vec![],
-                        format!(
-                            "consider adding `extern crate {ident}` to use the `{ident}` crate"
-                        ),
+                        vec![(
+                            self.current_crate_outer_attr_insert_span,
+                            format!("extern crate {ident};\n"),
+                        )],
+                        format!("consider importing the `{ident}` crate"),
                         Applicability::MaybeIncorrect,
                     )),
                 )
@@ -2059,11 +2069,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         parent_scope,
                         None,
                         ignore_binding,
+                        ignore_import,
                     )
                     .ok()
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
                 {
+                    assert!(ignore_import.is_none());
                     match self.resolve_ident_in_lexical_scope(
                         ident,
                         ns_to_try,
@@ -2084,6 +2096,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         None,
                         false,
                         ignore_binding,
+                        ignore_import,
                     )
                     .ok()
                 };
@@ -2125,6 +2138,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
             // Check whether the name refers to an item in the value namespace.
             let binding = if let Some(ribs) = ribs {
+                assert!(ignore_import.is_none());
                 self.resolve_ident_in_lexical_scope(
                     ident,
                     ValueNS,
@@ -2199,6 +2213,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 false,
                 ignore_binding,
+                ignore_import,
             ) {
                 let descr = binding.res().descr();
                 (format!("{descr} `{ident}` is not a crate or module"), suggestion)
@@ -2252,7 +2267,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> Option<(Vec<Segment>, Option<String>)> {
         // Replace first ident with `self` and check if that is valid.
         path[0].ident.name = kw::SelfLower;
-        let result = self.maybe_resolve_path(&path, None, parent_scope);
+        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
@@ -2271,7 +2286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> Option<(Vec<Segment>, Option<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Crate;
-        let result = self.maybe_resolve_path(&path, None, parent_scope);
+        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
             Some((
@@ -2302,7 +2317,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> Option<(Vec<Segment>, Option<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Super;
-        let result = self.maybe_resolve_path(&path, None, parent_scope);
+        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
@@ -2336,7 +2351,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         for name in extern_crate_names.into_iter() {
             // Replace first ident with a crate name and check if that is valid.
             path[0].ident.name = name;
-            let result = self.maybe_resolve_path(&path, None, parent_scope);
+            let result = self.maybe_resolve_path(&path, None, parent_scope, None);
             debug!(
                 "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
                 name, path, result
@@ -2502,12 +2517,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     /// Finds a cfg-ed out item inside `module` with the matching name.
-    pub(crate) fn find_cfg_stripped(
-        &mut self,
-        err: &mut Diag<'_>,
-        segment: &Symbol,
-        module: DefId,
-    ) {
+    pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
         let local_items;
         let symbols = if module.is_local() {
             local_items = self
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index dabed238838..5ee495da2d9 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -1,18 +1,15 @@
-use crate::{NameBinding, NameBindingKind, Resolver};
-use rustc_ast::ast;
-use rustc_ast::visit;
+use std::mem;
+
 use rustc_ast::visit::Visitor;
-use rustc_ast::Crate;
-use rustc_ast::EnumDef;
+use rustc_ast::{ast, visit, Crate, EnumDef};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::middle::privacy::Level;
-use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::ty::Visibility;
-use std::mem;
 use tracing::info;
 
+use crate::{NameBinding, NameBindingKind, Resolver};
+
 #[derive(Clone, Copy)]
 enum ParentId<'a> {
     Def(LocalDefId),
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 698147765b3..ad1841e3e89 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,11 +1,11 @@
-use rustc_errors::{codes::*, Applicability, ElidedLifetimeInPathSubdiag, MultiSpan};
+use rustc_errors::codes::*;
+use rustc_errors::{Applicability, ElidedLifetimeInPathSubdiag, MultiSpan};
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_span::{
-    symbol::{Ident, Symbol},
-    Span,
-};
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
 
-use crate::{late::PatternSource, Res};
+use crate::late::PatternSource;
+use crate::Res;
 
 #[derive(Diagnostic)]
 #[diag(resolve_generic_params_from_outer_item, code = E0401)]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index f1934ff184b..149c639efab 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1,29 +1,28 @@
 use rustc_ast::{self as ast, NodeId};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
-use rustc_middle::bug;
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::feature_err;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
-use rustc_span::sym;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use tracing::{debug, instrument};
+use Determinacy::*;
+use Namespace::*;
 
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
+use crate::imports::Import;
 use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
 use crate::macros::{sub_namespace_match, MacroRulesScope};
-use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
-use crate::{BindingKey, Used};
-use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
-use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
-
-use Determinacy::*;
-use Namespace::*;
+use crate::{
+    errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize,
+    ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding,
+    NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope,
+    ScopeSet, Segment, ToNameBinding, Used, Weak,
+};
 
 type Visibility = ty::Visibility<LocalDefId>;
 
@@ -353,6 +352,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 parent_scope,
                 finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                 ignore_binding,
+                None,
             );
             if let Ok(binding) = item {
                 // The ident resolves to an item.
@@ -366,6 +366,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             finalize,
             finalize.is_some(),
             ignore_binding,
+            None,
         )
         .ok()
         .map(LexicalScopeBinding::Item)
@@ -385,6 +386,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         finalize: Option<Finalize>,
         force: bool,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
         bitflags::bitflags! {
             #[derive(Clone, Copy)]
@@ -457,6 +459,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 parent_scope,
                                 true,
                                 force,
+                                ignore_import,
                             ) {
                                 Ok((Some(ext), _)) => {
                                     if ext.helper_attrs.contains(&ident.name) {
@@ -498,6 +501,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             parent_scope,
                             finalize,
                             ignore_binding,
+                            ignore_import,
                         );
                         match binding {
                             Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
@@ -520,6 +524,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             !matches!(scope_set, ScopeSet::Late(..)),
                             finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                             ignore_binding,
+                            ignore_import,
                         );
                         match binding {
                             Ok(binding) => {
@@ -587,6 +592,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 parent_scope,
                                 None,
                                 ignore_binding,
+                                ignore_import,
                             ) {
                                 if matches!(use_prelude, UsePrelude::Yes)
                                     || this.is_builtin_macro(binding.res())
@@ -740,8 +746,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import)
             .map_err(|(determinacy, _)| determinacy)
     }
 
@@ -754,9 +761,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding)
-            .map_err(|(determinacy, _)| determinacy)
+        self.resolve_ident_in_module_ext(
+            module,
+            ident,
+            ns,
+            parent_scope,
+            finalize,
+            ignore_binding,
+            ignore_import,
+        )
+        .map_err(|(determinacy, _)| determinacy)
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -768,6 +784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, (Determinacy, Weak)> {
         let tmp_parent_scope;
         let mut adjusted_parent_scope = parent_scope;
@@ -794,6 +811,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             false,
             finalize,
             ignore_binding,
+            ignore_import,
         )
     }
 
@@ -806,6 +824,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
         self.resolve_ident_in_module_unadjusted_ext(
             module,
@@ -815,6 +834,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             false,
             finalize,
             ignore_binding,
+            ignore_import,
         )
         .map_err(|(determinacy, _)| determinacy)
     }
@@ -833,6 +853,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // This binding should be ignored during in-module resolution, so that we don't get
         // "self-confirming" import resolutions during import validation and checking.
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, (Determinacy, Weak)> {
         let module = match module {
             ModuleOrUniformRoot::Module(module) => module,
@@ -845,6 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     finalize.is_some(),
                     ignore_binding,
+                    ignore_import,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -881,6 +903,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     finalize.is_some(),
                     ignore_binding,
+                    ignore_import,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -964,25 +987,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Check if one of single imports can still define the name,
         // if it can then our result is not determined and can be invalidated.
         for single_import in &resolution.single_imports {
-            let Some(import_vis) = single_import.vis.get() else {
-                // This branch handles a cycle in single imports, which occurs
-                // when we've previously **steal** the `vis` value during an import
-                // process.
+            if ignore_import == Some(*single_import) {
+                // This branch handles a cycle in single imports.
                 //
                 // For example:
                 // ```
                 // use a::b;
                 // use b as a;
                 // ```
-                // 1. Steal the `vis` in `use a::b` and attempt to locate `a` in the
+                // 1. Record `use a::b` as the `ignore_import` and attempt to locate `a` in the
                 //    current module.
                 // 2. Encounter the import `use b as a`, which is a `single_import` for `a`,
                 //    and try to find `b` in the current module.
                 // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`.
                 //    This leads to entering this branch.
                 continue;
-            };
-            if !self.is_accessible_from(import_vis, parent_scope.module) {
+            }
+            if !self.is_accessible_from(single_import.vis, parent_scope.module) {
                 continue;
             }
             if let Some(ignored) = ignore_binding
@@ -1024,6 +1045,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 &single_import.parent_scope,
                 None,
                 ignore_binding,
+                ignore_import,
             ) {
                 Err(Determined) => continue,
                 Ok(binding)
@@ -1072,10 +1094,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Check if one of glob imports can still define the name,
         // if it can then our "no resolution" result is not determined and can be invalidated.
         for glob_import in module.globs.borrow().iter() {
-            let Some(import_vis) = glob_import.vis.get() else {
+            if ignore_import == Some(*glob_import) {
                 continue;
-            };
-            if !self.is_accessible_from(import_vis, parent_scope.module) {
+            }
+            if !self.is_accessible_from(glob_import.vis, parent_scope.module) {
                 continue;
             }
             let module = match glob_import.imported_module.get() {
@@ -1102,6 +1124,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 adjusted_parent_scope,
                 None,
                 ignore_binding,
+                ignore_import,
             );
 
             match result {
@@ -1414,8 +1437,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
+        ignore_import: Option<Import<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import)
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1426,8 +1450,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
+        self.resolve_path_with_ribs(
+            path,
+            opt_ns,
+            parent_scope,
+            finalize,
+            None,
+            ignore_binding,
+            ignore_import,
+        )
     }
 
     pub(crate) fn resolve_path_with_ribs(
@@ -1438,6 +1471,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         finalize: Option<Finalize>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> PathResult<'a> {
         let mut module = None;
         let mut allow_super = true;
@@ -1540,10 +1574,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     parent_scope,
                     finalize,
                     ignore_binding,
+                    ignore_import,
                 )
             } else if let Some(ribs) = ribs
                 && let Some(TypeNS | ValueNS) = opt_ns
             {
+                assert!(ignore_import.is_none());
                 match self.resolve_ident_in_lexical_scope(
                     ident,
                     ns,
@@ -1572,6 +1608,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     finalize.is_some(),
                     ignore_binding,
+                    ignore_import,
                 )
             };
 
@@ -1646,6 +1683,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             parent_scope,
                             ribs,
                             ignore_binding,
+                            ignore_import,
                             module,
                             segment_idx,
                             ident,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d05326ee311..42171edf757 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1,32 +1,20 @@
 //! A bunch of methods and structures more or less related to resolving imports.
 
-use crate::diagnostics::{import_candidates, DiagMode, Suggestion};
-use crate::errors::{
-    CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
-    CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
-    ConsiderAddingMacroExport, ConsiderMarkingAsPub, IsNotDirectlyImportable,
-    ItemsInTraitsAreNotImportable,
-};
-use crate::Determinacy::{self, *};
-use crate::{module_to_string, names_to_string, ImportSuggestion};
-use crate::{AmbiguityError, Namespace::*};
-use crate::{AmbiguityKind, BindingKey, ResolutionError, Resolver, Segment};
-use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
-use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult, Used};
+use std::cell::Cell;
+use std::mem;
 
 use rustc_ast::NodeId;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
-use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan};
+use rustc_errors::codes::*;
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan};
 use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_hir::def_id::DefId;
-use rustc_middle::metadata::ModChild;
-use rustc_middle::metadata::Reexport;
-use rustc_middle::span_bug;
-use rustc_middle::ty;
+use rustc_middle::metadata::{ModChild, Reexport};
+use rustc_middle::{span_bug, ty};
 use rustc_session::lint::builtin::{
     AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE,
-    UNUSED_IMPORTS,
+    REDUNDANT_IMPORTS, UNUSED_IMPORTS,
 };
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -36,8 +24,20 @@ use rustc_span::Span;
 use smallvec::SmallVec;
 use tracing::debug;
 
-use std::cell::Cell;
-use std::mem;
+use crate::diagnostics::{import_candidates, DiagMode, Suggestion};
+use crate::errors::{
+    CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
+    CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
+    ConsiderAddingMacroExport, ConsiderMarkingAsPub, IsNotDirectlyImportable,
+    ItemsInTraitsAreNotImportable,
+};
+use crate::Determinacy::{self, *};
+use crate::Namespace::*;
+use crate::{
+    module_to_string, names_to_string, AmbiguityError, AmbiguityKind, BindingKey, Finalize,
+    ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind,
+    ParentScope, PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used,
+};
 
 type Res = def::Res<NodeId>;
 
@@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> {
         /// `source` in `use prefix::source as target`.
         source: Ident,
         /// `target` in `use prefix::source as target`.
+        /// It will directly use `source` when the format is `use prefix::source`.
         target: Ident,
         /// Bindings to which `source` refers to.
         source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
@@ -174,8 +175,7 @@ pub(crate) struct ImportData<'a> {
     pub module_path: Vec<Segment>,
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
-    pub vis: Cell<Option<ty::Visibility>>,
-    pub used: Cell<Option<Used>>,
+    pub vis: ty::Visibility,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -194,10 +194,6 @@ impl<'a> ImportData<'a> {
         }
     }
 
-    pub(crate) fn expect_vis(&self) -> ty::Visibility {
-        self.vis.get().expect("encountered cleared import visibility")
-    }
-
     pub(crate) fn id(&self) -> Option<NodeId> {
         match self.kind {
             ImportKind::Single { id, .. }
@@ -266,7 +262,7 @@ fn pub_use_of_private_extern_crate_hack(
     match (&import.kind, &binding.kind) {
         (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. })
             if let ImportKind::ExternCrate { id, .. } = binding_import.kind
-                && import.expect_vis().is_public() =>
+                && import.vis.is_public() =>
         {
             Some(id)
         }
@@ -278,7 +274,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// Given a binding and an import that resolves to it,
     /// return the corresponding binding defined by the import.
     pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> {
-        let import_vis = import.expect_vis().to_def_id();
+        let import_vis = import.vis.to_def_id();
         let vis = if binding.vis.is_at_least(import_vis, self.tcx)
             || pub_use_of_private_extern_crate_hack(import, binding).is_some()
         {
@@ -487,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             });
             self.record_use(target, dummy_binding, Used::Other);
         } else if import.imported_module.get().is_none() {
-            import.used.set(Some(Used::Other));
+            self.import_use_map.insert(import, Used::Other);
             if let Some(id) = import.id() {
                 self.used_imports.insert(id);
             }
@@ -772,11 +768,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let module = if let Some(module) = import.imported_module.get() {
             module
         } else {
-            // For better failure detection, pretend that the import will
-            // not define any names while resolving its module path.
-            let orig_vis = import.vis.take();
-            let path_res = self.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
-            import.vis.set(orig_vis);
+            let path_res = self.maybe_resolve_path(
+                &import.module_path,
+                None,
+                &import.parent_scope,
+                Some(import),
+            );
 
             match path_res {
                 PathResult::Module(module) => module,
@@ -806,16 +803,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         self.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
                 if let Err(Undetermined) = source_bindings[ns].get() {
-                    // For better failure detection, pretend that the import will
-                    // not define any names while resolving its module path.
-                    let orig_vis = import.vis.take();
                     let binding = this.maybe_resolve_ident_in_module(
                         module,
                         source,
                         ns,
                         &import.parent_scope,
+                        Some(import),
                     );
-                    import.vis.set(orig_vis);
                     source_bindings[ns].set(binding);
                 } else {
                     return;
@@ -854,7 +848,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// Optionally returns an unresolved import error. This error is buffered and used to
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: Import<'a>) -> Option<UnresolvedImportError> {
-        let orig_vis = import.vis.take();
         let ignore_binding = match &import.kind {
             ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
             _ => None,
@@ -873,11 +866,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             &import.parent_scope,
             Some(finalize),
             ignore_binding,
+            Some(import),
         );
 
         let no_ambiguity =
             ambiguity_errors_len(&self.ambiguity_errors) == prev_ambiguity_errors_len;
-        import.vis.set(orig_vis);
+
         let module = match path_res {
             PathResult::Module(module) => {
                 // Consistency checks, analogous to `finalize_macro_resolutions`.
@@ -1012,8 +1006,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     if !is_prelude
                         && let Some(max_vis) = max_vis.get()
-                        && let import_vis = import.expect_vis()
-                        && !max_vis.is_at_least(import_vis, self.tcx)
+                        && !max_vis.is_at_least(import.vis, self.tcx)
                     {
                         let def_id = self.local_def_id(id);
                         self.lint_buffer.buffer_lint(
@@ -1022,7 +1015,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             import.span,
                             BuiltinLintDiag::RedundantImportVisibility {
                                 max_vis: max_vis.to_string(def_id, self.tcx),
-                                import_vis: import_vis.to_string(def_id, self.tcx),
+                                import_vis: import.vis.to_string(def_id, self.tcx),
                                 span: import.span,
                             },
                         );
@@ -1037,9 +1030,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             // importing it if available.
             let mut path = import.module_path.clone();
             path.push(Segment::from_ident(ident));
-            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_binding)
-            {
+            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(
+                &path,
+                None,
+                &import.parent_scope,
+                Some(finalize),
+                ignore_binding,
+                None,
+            ) {
                 let res = module.res().map(|r| (r, ident));
                 for error in &mut self.privacy_errors[privacy_errors_len..] {
                     error.outermost_res = res;
@@ -1050,7 +1048,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut all_ns_err = true;
         self.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
-                let orig_vis = import.vis.take();
                 let binding = this.resolve_ident_in_module(
                     module,
                     ident,
@@ -1058,8 +1055,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     &import.parent_scope,
                     Some(Finalize { report_private: false, ..finalize }),
                     target_bindings[ns].get(),
+                    Some(import),
                 );
-                import.vis.set(orig_vis);
 
                 match binding {
                     Ok(binding) => {
@@ -1122,6 +1119,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         &import.parent_scope,
                         Some(finalize),
                         None,
+                        None,
                     );
                     if binding.is_ok() {
                         all_ns_failed = false;
@@ -1232,7 +1230,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut crate_private_reexport = false;
         self.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
-                if !binding.vis.is_at_least(import.expect_vis(), this.tcx) {
+                if !binding.vis.is_at_least(import.vis, this.tcx) {
                     reexport_error = Some((ns, binding));
                     if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
                         if binding_def_id.is_top_level_module() {
@@ -1348,7 +1346,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // module defined by a block).
         // Skip if the import is public or was used through non scope-based resolution,
         // e.g. through a module-relative path.
-        if import.used.get() == Some(Used::Other)
+        if self.import_use_map.get(&import) == Some(&Used::Other)
             || self.effective_visibilities.is_exported(self.local_def_id(id))
         {
             return false;
@@ -1369,6 +1367,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     None,
                     false,
                     target_bindings[ns].get(),
+                    None,
                 ) {
                     Ok(other_binding) => {
                         is_redundant = binding.res() == other_binding.res()
@@ -1387,14 +1386,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
             redundant_spans.sort();
             redundant_spans.dedup();
-            /* FIXME(unused_imports): Add this back as a new lint
-            self.lint_buffer.buffer_lint_with_diagnostic(
-                UNUSED_IMPORTS,
+            self.lint_buffer.buffer_lint(
+                REDUNDANT_IMPORTS,
                 id,
                 import.span,
                 BuiltinLintDiag::RedundantImport(redundant_spans, source),
             );
-            */
             return true;
         }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 51414d78596..4a70fc0f308 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -6,16 +6,18 @@
 //! If you wonder why there's no `early.rs`, that's because it's split into three files -
 //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
 
-use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
-use crate::{BindingKey, Used};
-use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
-use crate::{ResolutionError, Resolver, Segment, TyCtxt, UseError};
+use std::assert_matches::debug_assert_matches;
+use std::borrow::Cow;
+use std::collections::hash_map::Entry;
+use std::collections::BTreeSet;
+use std::mem::{replace, swap, take};
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{visit_opt, walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey};
+use rustc_errors::codes::*;
+use rustc_errors::{Applicability, DiagArgValue, IntoDiagArg, StashKey};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
@@ -32,10 +34,11 @@ use rustc_span::{BytePos, Span, SyntaxContext};
 use smallvec::{smallvec, SmallVec};
 use tracing::{debug, instrument, trace};
 
-use std::assert_matches::debug_assert_matches;
-use std::borrow::Cow;
-use std::collections::{hash_map::Entry, BTreeSet};
-use std::mem::{replace, swap, take};
+use crate::{
+    errors, path_names_to_string, rustdoc, BindingError, BindingKey, Finalize, LexicalScopeBinding,
+    Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult, ResolutionError, Resolver,
+    Segment, TyCtxt, UseError, Used,
+};
 
 mod diagnostics;
 
@@ -442,8 +445,8 @@ impl<'a> PathSource<'a> {
                 Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
                     // the case of `::some_crate()`
                     ExprKind::Path(_, path)
-                        if path.segments.len() == 2
-                            && path.segments[0].ident.name == kw::PathRoot =>
+                        if let [segment, _] = path.segments.as_slice()
+                            && segment.ident.name == kw::PathRoot =>
                     {
                         "external crate"
                     }
@@ -1385,6 +1388,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             finalize,
             Some(&self.ribs),
             None,
+            None,
         )
     }
 
@@ -2392,15 +2396,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     }
 
     fn future_proof_import(&mut self, use_tree: &UseTree) {
-        let segments = &use_tree.prefix.segments;
-        if !segments.is_empty() {
-            let ident = segments[0].ident;
+        if let [segment, rest @ ..] = use_tree.prefix.segments.as_slice() {
+            let ident = segment.ident;
             if ident.is_path_segment_keyword() || ident.span.is_rust_2015() {
                 return;
             }
 
             let nss = match use_tree.kind {
-                UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
+                UseTreeKind::Simple(..) if rest.is_empty() => &[TypeNS, ValueNS][..],
                 _ => &[TypeNS],
             };
             let report_error = |this: &Self, ns| {
@@ -2664,119 +2667,128 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         let mut function_type_rib = Rib::new(kind);
         let mut function_value_rib = Rib::new(kind);
         let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
-        let mut seen_bindings = FxHashMap::default();
-        // Store all seen lifetimes names from outer scopes.
-        let mut seen_lifetimes = FxHashSet::default();
-
-        // We also can't shadow bindings from the parent item
-        if let RibKind::AssocItem = kind {
-            let mut add_bindings_for_ns = |ns| {
-                let parent_rib = self.ribs[ns]
-                    .iter()
-                    .rfind(|r| matches!(r.kind, RibKind::Item(..)))
-                    .expect("associated item outside of an item");
-                seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
-            };
-            add_bindings_for_ns(ValueNS);
-            add_bindings_for_ns(TypeNS);
-        }
 
-        // Forbid shadowing lifetime bindings
-        for rib in self.lifetime_ribs.iter().rev() {
-            seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
-            if let LifetimeRibKind::Item = rib.kind {
-                break;
+        // Only check for shadowed bindings if we're declaring new params.
+        if !params.is_empty() {
+            let mut seen_bindings = FxHashMap::default();
+            // Store all seen lifetimes names from outer scopes.
+            let mut seen_lifetimes = FxHashSet::default();
+
+            // We also can't shadow bindings from associated parent items.
+            for ns in [ValueNS, TypeNS] {
+                for parent_rib in self.ribs[ns].iter().rev() {
+                    seen_bindings
+                        .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
+
+                    // Break at mod level, to account for nested items which are
+                    // allowed to shadow generic param names.
+                    if matches!(parent_rib.kind, RibKind::Module(..)) {
+                        break;
+                    }
+                }
             }
-        }
-
-        for param in params {
-            let ident = param.ident.normalize_to_macros_2_0();
-            debug!("with_generic_param_rib: {}", param.id);
 
-            if let GenericParamKind::Lifetime = param.kind
-                && let Some(&original) = seen_lifetimes.get(&ident)
-            {
-                diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
-                // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_param(param.id, LifetimeRes::Error);
-                continue;
+            // Forbid shadowing lifetime bindings
+            for rib in self.lifetime_ribs.iter().rev() {
+                seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
+                if let LifetimeRibKind::Item = rib.kind {
+                    break;
+                }
             }
 
-            match seen_bindings.entry(ident) {
-                Entry::Occupied(entry) => {
-                    let span = *entry.get();
-                    let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
-                    self.report_error(param.ident.span, err);
-                    let rib = match param.kind {
-                        GenericParamKind::Lifetime => {
-                            // Record lifetime res, so lowering knows there is something fishy.
-                            self.record_lifetime_param(param.id, LifetimeRes::Error);
-                            continue;
-                        }
-                        GenericParamKind::Type { .. } => &mut function_type_rib,
-                        GenericParamKind::Const { .. } => &mut function_value_rib,
-                    };
+            for param in params {
+                let ident = param.ident.normalize_to_macros_2_0();
+                debug!("with_generic_param_rib: {}", param.id);
 
-                    // Taint the resolution in case of errors to prevent follow up errors in typeck
-                    self.r.record_partial_res(param.id, PartialRes::new(Res::Err));
-                    rib.bindings.insert(ident, Res::Err);
+                if let GenericParamKind::Lifetime = param.kind
+                    && let Some(&original) = seen_lifetimes.get(&ident)
+                {
+                    diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
+                    // Record lifetime res, so lowering knows there is something fishy.
+                    self.record_lifetime_param(param.id, LifetimeRes::Error);
                     continue;
                 }
-                Entry::Vacant(entry) => {
-                    entry.insert(param.ident.span);
-                }
-            }
 
-            if param.ident.name == kw::UnderscoreLifetime {
-                self.r
-                    .dcx()
-                    .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
-                // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_param(param.id, LifetimeRes::Error);
-                continue;
-            }
+                match seen_bindings.entry(ident) {
+                    Entry::Occupied(entry) => {
+                        let span = *entry.get();
+                        let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
+                        self.report_error(param.ident.span, err);
+                        let rib = match param.kind {
+                            GenericParamKind::Lifetime => {
+                                // Record lifetime res, so lowering knows there is something fishy.
+                                self.record_lifetime_param(param.id, LifetimeRes::Error);
+                                continue;
+                            }
+                            GenericParamKind::Type { .. } => &mut function_type_rib,
+                            GenericParamKind::Const { .. } => &mut function_value_rib,
+                        };
 
-            if param.ident.name == kw::StaticLifetime {
-                self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
-                    span: param.ident.span,
-                    lifetime: param.ident,
-                });
-                // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_param(param.id, LifetimeRes::Error);
-                continue;
-            }
+                        // Taint the resolution in case of errors to prevent follow up errors in typeck
+                        self.r.record_partial_res(param.id, PartialRes::new(Res::Err));
+                        rib.bindings.insert(ident, Res::Err);
+                        continue;
+                    }
+                    Entry::Vacant(entry) => {
+                        entry.insert(param.ident.span);
+                    }
+                }
 
-            let def_id = self.r.local_def_id(param.id);
+                if param.ident.name == kw::UnderscoreLifetime {
+                    self.r
+                        .dcx()
+                        .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
+                    // Record lifetime res, so lowering knows there is something fishy.
+                    self.record_lifetime_param(param.id, LifetimeRes::Error);
+                    continue;
+                }
 
-            // Plain insert (no renaming).
-            let (rib, def_kind) = match param.kind {
-                GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
-                GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
-                GenericParamKind::Lifetime => {
-                    let res = LifetimeRes::Param { param: def_id, binder };
-                    self.record_lifetime_param(param.id, res);
-                    function_lifetime_rib.bindings.insert(ident, (param.id, res));
+                if param.ident.name == kw::StaticLifetime {
+                    self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
+                        span: param.ident.span,
+                        lifetime: param.ident,
+                    });
+                    // Record lifetime res, so lowering knows there is something fishy.
+                    self.record_lifetime_param(param.id, LifetimeRes::Error);
                     continue;
                 }
-            };
 
-            let res = match kind {
-                RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
-                RibKind::Normal => {
-                    // FIXME(non_lifetime_binders): Stop special-casing
-                    // const params to error out here.
-                    if self.r.tcx.features().non_lifetime_binders
-                        && matches!(param.kind, GenericParamKind::Type { .. })
-                    {
+                let def_id = self.r.local_def_id(param.id);
+
+                // Plain insert (no renaming).
+                let (rib, def_kind) = match param.kind {
+                    GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
+                    GenericParamKind::Const { .. } => {
+                        (&mut function_value_rib, DefKind::ConstParam)
+                    }
+                    GenericParamKind::Lifetime => {
+                        let res = LifetimeRes::Param { param: def_id, binder };
+                        self.record_lifetime_param(param.id, res);
+                        function_lifetime_rib.bindings.insert(ident, (param.id, res));
+                        continue;
+                    }
+                };
+
+                let res = match kind {
+                    RibKind::Item(..) | RibKind::AssocItem => {
                         Res::Def(def_kind, def_id.to_def_id())
-                    } else {
-                        Res::Err
                     }
-                }
-                _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
-            };
-            self.r.record_partial_res(param.id, PartialRes::new(res));
-            rib.bindings.insert(ident, res);
+                    RibKind::Normal => {
+                        // FIXME(non_lifetime_binders): Stop special-casing
+                        // const params to error out here.
+                        if self.r.tcx.features().non_lifetime_binders
+                            && matches!(param.kind, GenericParamKind::Type { .. })
+                        {
+                            Res::Def(def_kind, def_id.to_def_id())
+                        } else {
+                            Res::Err
+                        }
+                    }
+                    _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
+                };
+                self.r.record_partial_res(param.id, PartialRes::new(res));
+                rib.bindings.insert(ident, res);
+            }
         }
 
         self.lifetime_ribs.push(function_lifetime_rib);
@@ -3996,16 +4008,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             if this.should_report_errs() {
                 if candidates.is_empty() {
-                    if path.len() == 2 && prefix_path.len() == 1 {
+                    if path.len() == 2
+                        && let [segment] = prefix_path
+                    {
                         // Delay to check whether methond name is an associated function or not
                         // ```
                         // let foo = Foo {};
                         // foo::bar(); // possibly suggest to foo.bar();
                         //```
-                        err.stash(
-                            prefix_path[0].ident.span,
-                            rustc_errors::StashKey::CallAssocMethod,
-                        );
+                        err.stash(segment.ident.span, rustc_errors::StashKey::CallAssocMethod);
                     } else {
                         // When there is no suggested imports, we can just emit the error
                         // and suggestions immediately. Note that we bypass the usually error
@@ -4183,7 +4194,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
             let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
             if let Ok((_, res)) =
-                self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
+                self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
             {
                 return Ok(Some(PartialRes::new(res)));
             }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 941fb6436df..f778b0ee3ac 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,13 +1,8 @@
 // ignore-tidy-filelength
 
-use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
-use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
-use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
-use crate::ty::fast_reject::SimplifiedType;
-use crate::{errors, path_names_to_string};
-use crate::{Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{PathResult, PathSource, Segment};
-use rustc_hir::def::Namespace::{self, *};
+use std::borrow::Cow;
+use std::iter;
+use std::ops::Deref;
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{walk_ty, FnCtxt, FnKind, LifetimeCtxt, Visitor};
@@ -16,34 +11,38 @@ use rustc_ast::{
     MethodCall, NodeId, Path, Ty, TyKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
+    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
     SuggestionStyle,
 };
 use rustc_hir as hir;
+use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::{MissingLifetimeKind, PrimTy};
-use rustc_session::lint;
-use rustc_session::Session;
+use rustc_middle::ty;
+use rustc_session::{lint, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-
-use rustc_middle::ty;
-
-use std::borrow::Cow;
-use std::iter;
-use std::ops::Deref;
-
 use thin_vec::ThinVec;
 use tracing::debug;
 
 use super::NoConstantGenericsReason;
+use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
+use crate::late::{
+    AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
+    LifetimeUseSet, RibKind,
+};
+use crate::ty::fast_reject::SimplifiedType;
+use crate::{
+    errors, path_names_to_string, Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource,
+    Segment,
+};
 
 type Res = def::Res<ast::NodeId>;
 
@@ -651,14 +650,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         let typo_sugg = self
             .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
             .to_opt_suggestion();
-        if path.len() == 1
+        if let [segment] = path
             && !matches!(source, PathSource::Delegation)
             && self.self_type_is_available()
         {
             if let Some(candidate) =
                 self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
             {
-                let self_is_available = self.self_value_is_available(path[0].ident.span);
+                let self_is_available = self.self_value_is_available(segment.ident.span);
                 // Account for `Foo { field }` when suggesting `self.field` so we result on
                 // `Foo { field: self.field }`.
                 let pre = match source {
@@ -666,7 +665,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         if expr
                             .fields
                             .iter()
-                            .any(|f| f.ident == path[0].ident && f.is_shorthand) =>
+                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>
                     {
                         format!("{path_str}: ")
                     }
@@ -1259,8 +1258,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             )
                         })
                         .collect();
-                if targets.len() == 1 {
-                    let target = targets[0];
+                if let [target] = targets.as_slice() {
                     return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
                 }
             }
@@ -2059,6 +2057,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 ident,
                 ns,
                 &self.parent_scope,
+                None,
             ) {
                 let res = binding.res();
                 if filter_fn(res) {
@@ -2105,8 +2104,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         filter_fn: &impl Fn(Res) -> bool,
     ) -> TypoCandidate {
         let mut names = Vec::new();
-        if path.len() == 1 {
-            let mut ctxt = path.last().unwrap().ident.span.ctxt();
+        if let [segment] = path {
+            let mut ctxt = segment.ident.span.ctxt();
 
             // Search in lexical scope.
             // Walk backwards up the ribs in scope and collect candidates.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 3dcb83d65b0..02fdc1ae668 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -23,11 +23,25 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
+use std::cell::{Cell, RefCell};
+use std::collections::BTreeSet;
+use std::fmt;
+
+use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
+use effective_visibilities::EffectiveVisibilitiesVisitor;
+use errors::{
+    ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
+};
+use imports::{Import, ImportData, ImportKind, NameResolution};
+use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification};
+use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
-use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID};
-use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
+use rustc_ast::{
+    self as ast, attr, AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind,
+    NodeId, Path, CRATE_NODE_ID,
+};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::steal::Steal;
@@ -36,10 +50,10 @@ use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
 use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::NonMacroAttrKind;
-use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
-use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def::{
+    self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS,
+};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{PrimTy, TraitCandidate};
 use rustc_index::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
@@ -47,8 +61,10 @@ use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTools};
-use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed};
+use rustc_middle::ty::{
+    self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt,
+    ResolverOutputs, TyCtxt, TyCtxtFeed,
+};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
 use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
@@ -56,20 +72,8 @@ use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transpa
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
-use std::cell::{Cell, RefCell};
-use std::collections::BTreeSet;
-use std::fmt;
 use tracing::debug;
 
-use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
-use effective_visibilities::EffectiveVisibilitiesVisitor;
-use errors::{
-    ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
-};
-use imports::{Import, ImportData, ImportKind, NameResolution};
-use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification};
-use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
-
 type Res = def::Res<NodeId>;
 
 mod build_reduced_graph;
@@ -174,8 +178,8 @@ enum ImplTraitContext {
 
 /// Used for tracking import use types which will be used for redundant import checking.
 /// ### Used::Scope Example
-///  ```rust,ignore (redundant_imports)
-/// #![deny(unused_imports)]
+///  ```rust,compile_fail
+/// #![deny(redundant_imports)]
 /// use std::mem::drop;
 /// fn main() {
 ///     let s = Box::new(32);
@@ -1012,6 +1016,8 @@ pub struct Resolver<'a, 'tcx> {
     partial_res_map: NodeMap<PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
     import_res_map: NodeMap<PerNS<Option<Res>>>,
+    /// An import will be inserted into this map if it has been used.
+    import_use_map: FxHashMap<Import<'a>, Used>,
     /// Resolutions for labels (node IDs of their corresponding blocks or loops).
     label_res_map: NodeMap<NodeId>,
     /// Resolutions for lifetimes.
@@ -1125,9 +1131,6 @@ pub struct Resolver<'a, 'tcx> {
     /// Also includes of list of each fields visibility
     struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
 
-    /// Features declared for this crate.
-    declared_features: FxHashSet<Symbol>,
-
     lint_buffer: LintBuffer,
 
     next_node_id: NodeId,
@@ -1176,6 +1179,10 @@ pub struct Resolver<'a, 'tcx> {
     /// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations.
     /// Needed because glob delegations exclude explicitly defined names.
     impl_binding_keys: FxHashMap<LocalDefId, FxHashSet<BindingKey>>,
+
+    /// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo`
+    /// could be a crate that wasn't imported. For diagnostics use only.
+    current_crate_outer_attr_insert_span: Span,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1338,6 +1345,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         attrs: &[ast::Attribute],
         crate_span: Span,
+        current_crate_outer_attr_insert_span: Span,
         arenas: &'a ResolverArenas<'a>,
     ) -> Resolver<'a, 'tcx> {
         let root_def_id = CRATE_DEF_ID.to_def_id();
@@ -1393,7 +1401,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let registered_tools = tcx.registered_tools(());
 
-        let features = tcx.features();
         let pub_vis = ty::Visibility::<DefId>::Public;
         let edition = tcx.sess.edition();
 
@@ -1417,6 +1424,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             pat_span_map: Default::default(),
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
+            import_use_map: Default::default(),
             label_res_map: Default::default(),
             lifetimes_res_map: Default::default(),
             extra_lifetime_params_map: Default::default(),
@@ -1497,7 +1505,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             multi_segment_macro_resolutions: Default::default(),
             builtin_attrs: Default::default(),
             containers_deriving_copy: Default::default(),
-            declared_features: features.declared_features.clone(),
             lint_buffer: LintBuffer::default(),
             next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
@@ -1521,6 +1528,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             glob_delegation_invoc_ids: Default::default(),
             impl_unexpanded_invocations: Default::default(),
             impl_binding_keys: Default::default(),
+            current_crate_outer_attr_insert_span,
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1834,7 +1842,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     /// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors
-    fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool {
+    fn matches_previous_ambiguity_error(&self, ambi: &AmbiguityError<'_>) -> bool {
         for ambiguity_error in &self.ambiguity_errors {
             // if the span location and ident as well as its span are the same
             if ambiguity_error.kind == ambi.kind
@@ -1895,10 +1903,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
             }
-            let old_used = import.used.get();
-            let new_used = Some(used);
-            if new_used > old_used {
-                import.used.set(new_used);
+            let old_used = self.import_use_map.entry(import).or_insert(used);
+            if *old_used < used {
+                *old_used = used;
             }
             if let Some(id) = import.id() {
                 self.used_imports.insert(id);
@@ -2110,7 +2117,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         }
 
-        match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
+        match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
             PathResult::NonModule(path_res) => path_res.full_res(),
             PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
@@ -2194,6 +2201,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ident,
             ValueNS,
             parent_scope,
+            None,
         ) else {
             return;
         };
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index cb9bebd33d3..7203fbe4a0c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1,13 +1,9 @@
 //! A bunch of methods and structures more or less related to resolving macros and
 //! interface provided by `Resolver` to macro expander.
 
-use crate::errors::CannotDetermineMacroResolution;
-use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
-use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
-use crate::Namespace::*;
-use crate::{BindingKey, BuiltinMacroState, Determinacy, MacroData, NameBindingKind, Used};
-use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
-use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
+use std::cell::Cell;
+use std::mem;
+
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::{self as ast, attr, Crate, Inline, ItemKind, ModKind, NodeId};
 use rustc_ast_pretty::pprust;
@@ -15,8 +11,10 @@ use rustc_attr::StabilityLevel;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, StashKey};
-use rustc_expand::base::{Annotatable, DeriveResolution, Indeterminate, ResolverExpand};
-use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{
+    Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
+    SyntaxExtensionKind,
+};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{
     AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
@@ -24,8 +22,7 @@ use rustc_expand::expand::{
 use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_middle::middle::stability;
-use rustc_middle::ty::RegisteredTools;
-use rustc_middle::ty::{TyCtxt, Visibility};
+use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility};
 use rustc_session::lint::builtin::{
     LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, SOFT_UNSTABLE,
     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACROS, UNUSED_MACRO_RULES,
@@ -34,12 +31,21 @@ use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::edit_distance;
 use rustc_span::edition::Edition;
-use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId};
-use rustc_span::hygiene::{AstPass, MacroKind};
+use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use std::cell::Cell;
-use std::mem;
+
+use crate::errors::{
+    self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope,
+    MacroExpectedFound, RemoveSurroundingDerive,
+};
+use crate::imports::Import;
+use crate::Namespace::*;
+use crate::{
+    BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, MacroData, ModuleKind,
+    ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError,
+    Resolver, ScopeSet, Segment, ToNameBinding, Used,
+};
 
 type Res = def::Res<NodeId>;
 
@@ -103,8 +109,8 @@ pub(crate) fn sub_namespace_match(
 // `format!("{}", path)`, because that tries to insert
 // line-breaks and is slow.
 fn fast_print_path(path: &ast::Path) -> Symbol {
-    if path.segments.len() == 1 {
-        path.segments[0].ident.name
+    if let [segment] = path.segments.as_slice() {
+        segment.ident.name
     } else {
         let mut path_str = String::with_capacity(64);
         for (i, segment) in path.segments.iter().enumerate() {
@@ -394,6 +400,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
                         &parent_scope,
                         true,
                         force,
+                        None,
                     ) {
                         Ok((Some(ext), _)) => {
                             if !ext.helper_attrs.is_empty() {
@@ -546,6 +553,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             force,
             deleg_impl,
             invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
+            None,
         ) {
             Ok((Some(ext), res)) => (ext, res),
             Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -699,8 +707,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         trace: bool,
         force: bool,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
-        self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None, None)
+        self.resolve_macro_or_delegation_path(
+            path,
+            kind,
+            parent_scope,
+            trace,
+            force,
+            None,
+            None,
+            ignore_import,
+        )
     }
 
     fn resolve_macro_or_delegation_path(
@@ -712,6 +730,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         force: bool,
         deleg_impl: Option<LocalDefId>,
         invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
         let path_span = ast_path.span;
         let mut path = Segment::from_path(ast_path);
@@ -719,16 +738,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Possibly apply the macro helper hack
         if deleg_impl.is_none()
             && kind == Some(MacroKind::Bang)
-            && path.len() == 1
-            && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
+            && let [segment] = path.as_slice()
+            && segment.ident.span.ctxt().outer_expn_data().local_inner_macros
         {
-            let root = Ident::new(kw::DollarCrate, path[0].ident.span);
+            let root = Ident::new(kw::DollarCrate, segment.ident.span);
             path.insert(0, Segment::from_ident(root));
         }
 
         let res = if deleg_impl.is_some() || path.len() > 1 {
             let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS };
-            let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) {
+            let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
                 PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
                 PathResult::NonModule(..)
@@ -763,6 +782,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 force,
                 None,
+                None,
             );
             if let Err(Determinacy::Undetermined) = binding {
                 return Err(Determinacy::Undetermined);
@@ -847,6 +867,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 &parent_scope,
                 Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
+                None,
             ) {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
                     check_consistency(self, &path, path_span, kind, initial_res, res)
@@ -866,7 +887,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         if let PathResult::Failed { span, label, module, .. } = path_res {
                             // try to suggest if it's not a macro, maybe a function
                             if let PathResult::NonModule(partial_res) =
-                                self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+                                self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None)
                                 && partial_res.unresolved_segments() == 0
                             {
                                 let sm = self.tcx.sess.source_map();
@@ -916,6 +937,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
                 None,
+                None,
             ) {
                 Ok(binding) => {
                     let initial_res = initial_binding.map(|initial_binding| {
@@ -961,6 +983,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
                 None,
+                None,
             );
         }
     }
@@ -978,7 +1001,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let feature = stability.feature;
 
                 let is_allowed = |feature| {
-                    self.declared_features.contains(&feature) || span.allows_unstable(feature)
+                    self.tcx.features().declared_features.contains(&feature)
+                        || span.allows_unstable(feature)
                 };
                 let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
                 if !is_allowed(feature) && !allowed_by_implication {
@@ -1065,6 +1089,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 false,
                 None,
+                None,
             );
             if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) {
                 self.tcx.sess.psess.buffer_lint(
@@ -1138,7 +1163,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let mut indeterminate = false;
         for ns in namespaces {
-            match self.maybe_resolve_path(path, Some(*ns), &parent_scope) {
+            match self.maybe_resolve_path(path, Some(*ns), &parent_scope, None) {
                 PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
                 PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
                     return Ok(true);
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 4c49c15c472..de4fc5c27d4 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -1,3 +1,6 @@
+use std::mem;
+use std::ops::Range;
+
 use pulldown_cmark::{
     BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, Options, Parser, Tag,
 };
@@ -8,8 +11,6 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
-use std::mem;
-use std::ops::Range;
 use tracing::{debug, trace};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 190ea443189..61de338eab1 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -5,9 +5,9 @@
 //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
 //! see design document in the tracking issue #89653.
 
-use rustc_data_structures::base_n::ToBaseN;
-use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
-use rustc_data_structures::base_n::CASE_INSENSITIVE;
+use std::fmt::Write as _;
+
+use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY, CASE_INSENSITIVE};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_middle::bug;
@@ -20,7 +20,6 @@ use rustc_span::def_id::DefId;
 use rustc_span::sym;
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
-use std::fmt::Write as _;
 use tracing::instrument;
 
 use crate::cfi::typeid::itanium_cxx_abi::transform::{TransformTy, TransformTyOptions};
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
index ac664c53f44..cb15c67b895 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
@@ -6,7 +6,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
 use tracing::instrument;
 
@@ -112,11 +112,12 @@ pub fn typeid_for_instance<'tcx>(
     instance: Instance<'tcx>,
     options: TypeIdOptions,
 ) -> String {
+    assert!(!instance.has_non_region_param(), "{instance:#?} must be fully monomorphic");
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
     let instance = transform_instance(tcx, instance, transform_ty_options);
     let fn_abi = tcx
-        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
+        .fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty())))
         .unwrap_or_else(|error| {
             bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
         });
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 9b05576d721..e628c17aca3 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -4,6 +4,8 @@
 //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
 //! see design document in the tracking issue #89653.
 
+use std::iter;
+
 use rustc_hir as hir;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
@@ -12,9 +14,9 @@ use rustc_middle::ty::{
     self, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy, List, TraitRef, Ty,
     TyCtxt, TypeFoldable, TypeVisitableExt, UintTy,
 };
-use rustc_span::{def_id::DefId, sym};
+use rustc_span::def_id::DefId;
+use rustc_span::sym;
 use rustc_trait_selection::traits;
-use std::iter;
 use tracing::{debug, instrument};
 
 use crate::cfi::typeid::itanium_cxx_abi::encode::EncodeTyOptions;
@@ -230,6 +232,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
             tcx.associated_items(super_poly_trait_ref.def_id())
                 .in_definition_order()
                 .filter(|item| item.kind == ty::AssocKind::Type)
+                .filter(|item| !tcx.generics_require_sized_self(item.def_id))
                 .map(move |assoc_ty| {
                     super_poly_trait_ref.map_bound(|super_trait_ref| {
                         let alias_ty =
diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs
index bfe907e3cf6..b47a091ab64 100644
--- a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs
+++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs
@@ -4,9 +4,10 @@
 //! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler,
 //! see the tracking issue #123479.
 
+use std::hash::Hasher;
+
 use rustc_middle::ty::{Instance, InstanceKind, ReifyReason, Ty, TyCtxt};
 use rustc_target::abi::call::FnAbi;
-use std::hash::Hasher;
 use twox_hash::XxHash64;
 
 pub use crate::cfi::typeid::{itanium_cxx_abi, TypeIdOptions};
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index 44324804468..aa7c2858466 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -1,9 +1,8 @@
-use crate::opaque::MemDecoder;
-use crate::serialize::Decoder;
-
 // 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 crate::int_overflow::DebugStrictAdd;
+use crate::opaque::MemDecoder;
+use crate::serialize::Decoder;
 
 /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type
 pub const fn max_leb128_len<T>() -> usize {
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index d27dfd88824..d8609ccfe42 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -1,15 +1,14 @@
-use crate::leb128;
-use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fs::File;
 use std::io::{self, Write};
 use std::marker::PhantomData;
 use std::ops::Range;
-use std::path::Path;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
 // 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 crate::int_overflow::DebugStrictAdd;
+use crate::leb128;
+use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
 
 // -----------------------------------------------------------------------------
 // Encoder
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index c84bb26735c..2d37f5bdab8 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -1,6 +1,5 @@
 //! Support code for encoding and decoding types.
 
-use smallvec::{Array, SmallVec};
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
@@ -10,6 +9,8 @@ use std::num::NonZero;
 use std::path;
 use std::rc::Rc;
 use std::sync::Arc;
+
+use smallvec::{Array, SmallVec};
 use thin_vec::ThinVec;
 
 /// A byte that [cannot occur in UTF8 sequences][utf8]. Used to mark the end of a string.
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index fafe4b91a95..b06a28d7c95 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -1,6 +1,5 @@
 use rustc_serialize::leb128::*;
-use rustc_serialize::opaque::MemDecoder;
-use rustc_serialize::opaque::MAGIC_END_BYTES;
+use rustc_serialize::opaque::{MemDecoder, MAGIC_END_BYTES};
 use rustc_serialize::Decoder;
 
 macro_rules! impl_test_unsigned_leb128 {
diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs
index 833151d82be..0543e176ae5 100644
--- a/compiler/rustc_serialize/tests/opaque.rs
+++ b/compiler/rustc_serialize/tests/opaque.rs
@@ -1,10 +1,11 @@
 #![allow(rustc::internal)]
 
+use std::fmt::Debug;
+use std::fs;
+
 use rustc_macros::{Decodable_Generic, Encodable_Generic};
 use rustc_serialize::opaque::{FileEncoder, MemDecoder};
 use rustc_serialize::{Decodable, Encodable};
-use std::fmt::Debug;
-use std::fs;
 
 #[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)]
 struct Struct {
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 93839fa1186..3668fe4f0a8 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -1,9 +1,10 @@
+use std::cmp;
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lock;
 use rustc_span::def_id::DefId;
 use rustc_span::Symbol;
 use rustc_target::abi::{Align, Size};
-use std::cmp;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct VariantInfo {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e748d1ff47b..95d171409d8 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3,13 +3,17 @@
 
 #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 
-pub use crate::options::*;
+use std::collections::btree_map::{
+    Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
+};
+use std::collections::{BTreeMap, BTreeSet};
+use std::ffi::OsStr;
+use std::hash::Hash;
+use std::path::{Path, PathBuf};
+use std::str::{self, FromStr};
+use std::sync::LazyLock;
+use std::{fmt, fs, iter};
 
-use crate::errors::FileWriteFail;
-use crate::search_paths::SearchPath;
-use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use crate::{filesearch, lint, HashStableContext};
-use crate::{EarlyDiagCtxt, Session};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
 use rustc_errors::emitter::HumanReadableErrorType;
@@ -19,22 +23,17 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
 use rustc_span::source_map::FilePathMapping;
 use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm};
-use rustc_target::spec::{FramePointer, LinkSelfContainedComponents, LinkerFeatures};
-use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
-use std::collections::btree_map::{
-    Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
+use rustc_target::spec::{
+    FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTriple,
 };
-use std::collections::{BTreeMap, BTreeSet};
-use std::ffi::OsStr;
-use std::fmt;
-use std::fs;
-use std::hash::Hash;
-use std::iter;
-use std::path::{Path, PathBuf};
-use std::str::{self, FromStr};
-use std::sync::LazyLock;
 use tracing::debug;
 
+use crate::errors::FileWriteFail;
+pub use crate::options::*;
+use crate::search_paths::SearchPath;
+use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
+use crate::{filesearch, lint, EarlyDiagCtxt, HashStableContext, Session};
+
 mod cfg;
 pub mod sigpipe;
 
@@ -603,7 +602,7 @@ impl OutputType {
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum ErrorOutputType {
     /// Output meant for the consumption of humans.
-    HumanReadable(HumanReadableErrorType),
+    HumanReadable(HumanReadableErrorType, ColorConfig),
     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
     Json {
         /// Render the JSON in a human readable way (with indents and newlines).
@@ -611,12 +610,13 @@ pub enum ErrorOutputType {
         /// The JSON output includes a `rendered` field that includes the rendered
         /// human output.
         json_rendered: HumanReadableErrorType,
+        color_config: ColorConfig,
     },
 }
 
 impl Default for ErrorOutputType {
     fn default() -> Self {
-        Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
+        Self::HumanReadable(HumanReadableErrorType::Default, ColorConfig::Auto)
     }
 }
 
@@ -839,10 +839,14 @@ pub enum Input {
 
 impl Input {
     pub fn filestem(&self) -> &str {
-        match *self {
-            Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
-            Input::Str { .. } => "rust_out",
+        if let Input::File(ifile) = self {
+            // If for some reason getting the file stem as a UTF-8 string fails,
+            // then fallback to a fixed name.
+            if let Some(name) = ifile.file_stem().and_then(OsStr::to_str) {
+                return name;
+            }
         }
+        "rust_out"
     }
 
     pub fn source_name(&self) -> FileName {
@@ -1301,7 +1305,10 @@ pub(crate) const fn default_lib_output() -> CrateType {
 }
 
 pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
-    // Combine the configuration requested by the session (command line) with
+    // First disallow some configuration given on the command line
+    cfg::disallow_cfgs(sess, &user_cfg);
+
+    // Then combine the configuration requested by the session (command line) with
     // some default and generated configuration items.
     user_cfg.extend(cfg::default_configuration(sess));
     user_cfg
@@ -1625,6 +1632,7 @@ pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Col
 /// Possible json config files
 pub struct JsonConfig {
     pub json_rendered: HumanReadableErrorType,
+    pub json_color: ColorConfig,
     json_artifact_notifications: bool,
     pub json_unused_externs: JsonUnusedExterns,
     json_future_incompat: bool,
@@ -1662,8 +1670,7 @@ impl JsonUnusedExterns {
 /// The first value returned is how to render JSON diagnostics, and the second
 /// is whether or not artifact notifications are enabled.
 pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
-    let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
-        HumanReadableErrorType::Default;
+    let mut json_rendered = HumanReadableErrorType::Default;
     let mut json_color = ColorConfig::Never;
     let mut json_artifact_notifications = false;
     let mut json_unused_externs = JsonUnusedExterns::No;
@@ -1690,7 +1697,8 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
     }
 
     JsonConfig {
-        json_rendered: json_rendered(json_color),
+        json_rendered,
+        json_color,
         json_artifact_notifications,
         json_unused_externs,
         json_future_incompat,
@@ -1702,6 +1710,7 @@ pub fn parse_error_format(
     early_dcx: &mut EarlyDiagCtxt,
     matches: &getopts::Matches,
     color: ColorConfig,
+    json_color: ColorConfig,
     json_rendered: HumanReadableErrorType,
 ) -> ErrorOutputType {
     // We need the `opts_present` check because the driver will send us Matches
@@ -1711,18 +1720,22 @@ pub fn parse_error_format(
     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
         match matches.opt_str("error-format").as_deref() {
             None | Some("human") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
+                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color)
             }
             Some("human-annotate-rs") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
+                ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, color)
             }
-            Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
-            Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
-            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
-
+            Some("json") => {
+                ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
+            }
+            Some("pretty-json") => {
+                ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
+            }
+            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short, color),
             Some(arg) => {
                 early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
-                    HumanReadableErrorType::Default(color),
+                    HumanReadableErrorType::Default,
+                    color,
                 ));
                 early_dcx.early_fatal(format!(
                     "argument for `--error-format` must be `human`, `json` or \
@@ -1731,7 +1744,7 @@ pub fn parse_error_format(
             }
         }
     } else {
-        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
+        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color)
     };
 
     match error_format {
@@ -1785,7 +1798,7 @@ fn check_error_format_stability(
         if let ErrorOutputType::Json { pretty: true, .. } = error_format {
             early_dcx.early_fatal("`--error-format=pretty-json` is unstable");
         }
-        if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
+        if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, _) =
             error_format
         {
             early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable");
@@ -2386,12 +2399,13 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let JsonConfig {
         json_rendered,
+        json_color,
         json_artifact_notifications,
         json_unused_externs,
         json_future_incompat,
     } = parse_json(early_dcx, matches);
 
-    let error_format = parse_error_format(early_dcx, matches, color, json_rendered);
+    let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
 
     early_dcx.abort_if_error_and_set_error_format(error_format);
 
@@ -2765,9 +2779,10 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
 }
 
 pub mod nightly_options {
+    use rustc_feature::UnstableFeatures;
+
     use super::{OptionStability, RustcOptGroup};
     use crate::EarlyDiagCtxt;
-    use rustc_feature::UnstableFeatures;
 
     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
         match_is_nightly_build(matches)
@@ -2960,6 +2975,22 @@ pub enum WasiExecModel {
 /// we have an opt-in scheme here, so one is hopefully forced to think about
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
+    use std::collections::BTreeMap;
+    use std::hash::{DefaultHasher, Hash};
+    use std::num::NonZero;
+    use std::path::PathBuf;
+
+    use rustc_data_structures::fx::FxIndexMap;
+    use rustc_data_structures::stable_hasher::Hash64;
+    use rustc_errors::LanguageIdentifier;
+    use rustc_feature::UnstableFeatures;
+    use rustc_span::edition::Edition;
+    use rustc_span::RealFileName;
+    use rustc_target::spec::{
+        CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
+        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi,
+    };
+
     use super::{
         BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
         CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn,
@@ -2971,20 +3002,6 @@ pub(crate) mod dep_tracking {
     };
     use crate::lint;
     use crate::utils::NativeLib;
-    use rustc_data_structures::fx::FxIndexMap;
-    use rustc_data_structures::stable_hasher::Hash64;
-    use rustc_errors::LanguageIdentifier;
-    use rustc_feature::UnstableFeatures;
-    use rustc_span::edition::Edition;
-    use rustc_span::RealFileName;
-    use rustc_target::spec::{
-        CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
-        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi,
-    };
-    use std::collections::BTreeMap;
-    use std::hash::{DefaultHasher, Hash};
-    use std::num::NonZero;
-    use std::path::PathBuf;
 
     pub(crate) trait DepTrackingHash {
         fn hash(
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index 2fa04bbe345..a64b1e21e9e 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -17,20 +17,23 @@
 //!  - Add the activation logic in [`default_configuration`]
 //!  - Add the cfg to [`CheckCfg::fill_well_known`] (and related files),
 //!    so that the compiler can know the cfg is expected
+//!  - Add the cfg in [`disallow_cfgs`] to disallow users from setting it via `--cfg`
 //!  - Add the feature gating in `compiler/rustc_feature/src/builtin_attrs.rs`
 
+use std::hash::Hash;
+use std::iter;
+
+use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::Align;
-use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet};
-use rustc_target::spec::{Target, TargetTriple, TARGETS};
+use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target, TargetTriple, TARGETS};
 
 use crate::config::CrateType;
 use crate::Session;
 
-use std::hash::Hash;
-use std::iter;
-
 /// The parsed `--cfg` options that define the compilation environment of the
 /// crate, used to drive conditional compilation.
 ///
@@ -83,6 +86,67 @@ impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
     }
 }
 
+/// Disallow builtin cfgs from the CLI.
+pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
+    let disallow = |cfg: &(Symbol, Option<Symbol>), controlled_by| {
+        let cfg_name = cfg.0;
+        let cfg = if let Some(value) = cfg.1 {
+            format!(r#"{}="{}""#, cfg_name, value)
+        } else {
+            format!("{}", cfg_name)
+        };
+        sess.psess.opt_span_buffer_lint(
+            EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
+            None,
+            ast::CRATE_NODE_ID,
+            BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by },
+        )
+    };
+
+    // We want to restrict setting builtin cfgs that will produce incoherent behavior
+    // between the cfg and the rustc cli flag that sets it.
+    //
+    // The tests are in tests/ui/cfg/disallowed-cli-cfgs.rs.
+
+    // By-default all builtin cfgs are disallowed, only those are allowed:
+    //  - test: as it makes sense to the have the `test` cfg active without the builtin
+    //          test harness. See Cargo `harness = false` config.
+    //
+    // Cargo `--cfg test`: https://github.com/rust-lang/cargo/blob/bc89bffa5987d4af8f71011c7557119b39e44a65/src/cargo/core/compiler/mod.rs#L1124
+
+    for cfg in user_cfgs {
+        match cfg {
+            (sym::overflow_checks, None) => disallow(cfg, "-C overflow-checks"),
+            (sym::debug_assertions, None) => disallow(cfg, "-C debug-assertions"),
+            (sym::ub_checks, None) => disallow(cfg, "-Z ub-checks"),
+            (sym::sanitize, None | Some(_)) => disallow(cfg, "-Z sanitizer"),
+            (
+                sym::sanitizer_cfi_generalize_pointers | sym::sanitizer_cfi_normalize_integers,
+                None | Some(_),
+            ) => disallow(cfg, "-Z sanitizer=cfi"),
+            (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"),
+            (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"),
+            (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"),
+            (sym::unix, None)
+            | (sym::windows, None)
+            | (sym::relocation_model, Some(_))
+            | (sym::target_abi, None | Some(_))
+            | (sym::target_arch, Some(_))
+            | (sym::target_endian, Some(_))
+            | (sym::target_env, None | Some(_))
+            | (sym::target_family, Some(_))
+            | (sym::target_os, Some(_))
+            | (sym::target_pointer_width, Some(_))
+            | (sym::target_vendor, None | Some(_))
+            | (sym::target_has_atomic, Some(_))
+            | (sym::target_has_atomic_equal_alignment, Some(_))
+            | (sym::target_has_atomic_load_store, Some(_))
+            | (sym::target_thread_local, None) => disallow(cfg, "--target"),
+            _ => {}
+        }
+    }
+}
+
 /// Generate the default configs for a given session
 pub(crate) fn default_configuration(sess: &Session) -> Cfg {
     let mut ret = Cfg::default();
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 2c20c3f0e1a..da7a82fee94 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -2,8 +2,9 @@
 //! are *mostly* used as a part of that interface, but these should
 //! probably get a better home if someone can find one.
 
-use crate::search_paths::PathKind;
-use crate::utils::NativeLibKind;
+use std::any::Any;
+use std::path::PathBuf;
+
 use rustc_ast as ast;
 use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock};
 use rustc_hir::def_id::{
@@ -15,8 +16,8 @@ use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-use std::any::Any;
-use std::path::PathBuf;
+use crate::search_paths::PathKind;
+use crate::utils::NativeLibKind;
 
 // lonely orphan structs and enums looking for a better home
 
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 4cbc1b57022..5cc54a5855b 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -2,15 +2,17 @@ use std::num::NonZero;
 
 use rustc_ast::token;
 use rustc_ast::util::literal::LitError;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed,
-    Level, MultiSpan,
+    Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level,
+    MultiSpan,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
-use crate::{config::CrateType, parse::ParseSess};
+use crate::config::CrateType;
+use crate::parse::ParseSess;
 
 pub(crate) struct FeatureGateError {
     pub(crate) span: MultiSpan,
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 6f63776bedc..63ca5fefd9f 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -1,13 +1,14 @@
 //! A module for searching for libraries
 
-use crate::search_paths::{PathKind, SearchPath};
+use std::path::{Path, PathBuf};
+use std::{env, fs};
+
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use smallvec::{smallvec, SmallVec};
-use std::env;
-use std::fs;
-use std::path::{Path, PathBuf};
 use tracing::debug;
 
+use crate::search_paths::{PathKind, SearchPath};
+
 #[derive(Clone)]
 pub struct FileSearch<'a> {
     sysroot: &'a Path,
@@ -18,6 +19,11 @@ pub struct FileSearch<'a> {
 }
 
 impl<'a> FileSearch<'a> {
+    pub fn cli_search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
+        let kind = self.kind;
+        self.cli_search_paths.iter().filter(move |sp| sp.kind.matches(kind))
+    }
+
     pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
         let kind = self.kind;
         self.cli_search_paths
@@ -129,12 +135,10 @@ fn current_dll_path() -> Result<PathBuf, String> {
     use std::io;
     use std::os::windows::prelude::*;
 
-    use windows::{
-        core::PCWSTR,
-        Win32::Foundation::HMODULE,
-        Win32::System::LibraryLoader::{
-            GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-        },
+    use windows::core::PCWSTR;
+    use windows::Win32::Foundation::HMODULE;
+    use windows::Win32::System::LibraryLoader::{
+        GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
     };
 
     let mut module = HMODULE::default();
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 8fd1876ff1d..df72e2430fd 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1,26 +1,26 @@
-use crate::config::*;
-use crate::search_paths::SearchPath;
-use crate::utils::NativeLib;
-use crate::{lint, EarlyDiagCtxt};
+use std::collections::BTreeMap;
+use std::hash::{DefaultHasher, Hasher};
+use std::num::{IntErrorKind, NonZero};
+use std::path::PathBuf;
+use std::str;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_data_structures::stable_hasher::Hash64;
-use rustc_errors::ColorConfig;
-use rustc_errors::{LanguageIdentifier, TerminalUrl};
+use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl};
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::Edition;
-use rustc_span::RealFileName;
-use rustc_span::SourceFileHashAlgorithm;
+use rustc_span::{RealFileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{
     CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
     RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
     WasmCAbi,
 };
-use std::collections::BTreeMap;
-use std::hash::{DefaultHasher, Hasher};
-use std::num::{IntErrorKind, NonZero};
-use std::path::PathBuf;
-use std::str;
+
+use crate::config::*;
+use crate::search_paths::SearchPath;
+use crate::utils::NativeLib;
+use crate::{lint, EarlyDiagCtxt};
 
 macro_rules! insert {
     ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => {
@@ -447,9 +447,10 @@ mod desc {
 }
 
 mod parse {
-    pub(crate) use super::*;
     use std::str::FromStr;
 
+    pub(crate) use super::*;
+
     /// This is for boolean options that don't take a value and start with
     /// `no-`. This style of option is deprecated.
     pub(crate) fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
@@ -911,16 +912,9 @@ mod parse {
         match v {
             None => false,
             Some(s) => {
-                let parts = s.split('=').collect::<Vec<_>>();
-                if parts.len() != 2 {
-                    return false;
-                }
-                let crate_name = parts[0].to_string();
-                let fuel = parts[1].parse::<u64>();
-                if fuel.is_err() {
-                    return false;
-                }
-                *slot = Some((crate_name, fuel.unwrap()));
+                let [crate_name, fuel] = *s.split('=').collect::<Vec<_>>() else { return false };
+                let Ok(fuel) = fuel.parse::<u64>() else { return false };
+                *slot = Some((crate_name.to_string(), fuel));
                 true
             }
         }
@@ -1826,6 +1820,8 @@ options! {
         the same values as the target option of the same name"),
     meta_stats: bool = (false, parse_bool, [UNTRACKED],
         "gather metadata statistics (default: no)"),
+    metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "stores metrics about the errors being emitted by rustc to disk"),
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index 9a5314312e5..c2ca19e563c 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -1,16 +1,18 @@
 //! Related to out filenames of compilation (e.g. binaries).
 
+use std::path::Path;
+
+use rustc_ast::{self as ast, attr};
+use rustc_errors::FatalError;
+use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
+
 use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use crate::errors::{
     self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
     InvalidCharacterInCrateName, InvalidCrateNameHelp,
 };
 use crate::Session;
-use rustc_ast::{self as ast, attr};
-use rustc_errors::FatalError;
-use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol};
-use std::path::Path;
 
 pub fn out_filename(
     sess: &Session,
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 200505aaea2..d6c58e9d1be 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -1,15 +1,9 @@
 //! Contains `ParseSess` which holds state living beyond what one `Parser` might.
 //! It also serves as an input to the parser itself.
 
-use crate::config::{Cfg, CheckCfg};
-use crate::errors::{
-    CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp,
-    FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler,
-};
-use crate::lint::{
-    builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiag, Lint, LintId,
-};
-use crate::Session;
+use std::str;
+
+use rustc_ast::attr::AttrIdGenerator;
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
@@ -24,8 +18,14 @@ use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::{Span, Symbol};
 
-use rustc_ast::attr::AttrIdGenerator;
-use std::str;
+use crate::config::{Cfg, CheckCfg};
+use crate::errors::{
+    CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp,
+    FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler,
+};
+use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION;
+use crate::lint::{BufferedEarlyLint, BuiltinLintDiag, Lint, LintId};
+use crate::Session;
 
 /// Collected spans during parsing for places where a certain feature was
 /// used and should be feature gated accordingly in `check_crate`.
@@ -307,9 +307,19 @@ impl ParseSess {
         node_id: NodeId,
         diagnostic: BuiltinLintDiag,
     ) {
+        self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic)
+    }
+
+    pub fn opt_span_buffer_lint(
+        &self,
+        lint: &'static Lint,
+        span: Option<MultiSpan>,
+        node_id: NodeId,
+        diagnostic: BuiltinLintDiag,
+    ) {
         self.buffered_lints.with_lock(|buffered_lints| {
             buffered_lints.push(BufferedEarlyLint {
-                span: span.into(),
+                span,
                 node_id,
                 lint_id: LintId::of(lint),
                 diagnostic,
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index 5e8adffc249..d65b1b8b3f1 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -1,8 +1,10 @@
-use crate::filesearch::make_target_lib_path;
-use crate::EarlyDiagCtxt;
+use std::path::{Path, PathBuf};
+
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_target::spec::TargetTriple;
-use std::path::{Path, PathBuf};
+
+use crate::filesearch::make_target_lib_path;
+use crate::EarlyDiagCtxt;
 
 #[derive(Clone, Debug)]
 pub struct SearchPath {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 89d029fa6e0..672dddf871e 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1,14 +1,11 @@
-use crate::code_stats::CodeStats;
-pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
-use crate::config::{
-    self, CoverageLevel, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName,
-    OutputType, RemapPathScopeComponents, SwitchWithOptPath,
-};
-use crate::config::{ErrorOutputType, Input};
-use crate::errors;
-use crate::parse::{add_feature_diagnostics, ParseSess};
-use crate::search_paths::{PathKind, SearchPath};
-use crate::{filesearch, lint};
+use std::any::Any;
+use std::ops::{Div, Mul};
+use std::path::{Path, PathBuf};
+use std::str::FromStr;
+use std::sync::atomic::AtomicBool;
+use std::sync::atomic::Ordering::SeqCst;
+use std::sync::Arc;
+use std::{env, fmt, io};
 
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
@@ -18,33 +15,34 @@ use rustc_data_structures::sync::{
     AtomicU64, DynSend, DynSync, Lock, Lrc, MappedReadGuard, ReadGuard, RwLock,
 };
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
+use rustc_errors::codes::*;
 use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter, HumanReadableErrorType};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
-    codes::*, fallback_fluent_bundle, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic,
+    fallback_fluent_bundle, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic,
     ErrorGuaranteed, FatalAbort, FluentBundle, LazyFallbackBundle, TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
-use rustc_span::{FileNameDisplayPreference, RealFileName};
-use rustc_span::{Span, Symbol};
+use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol};
 use rustc_target::asm::InlineAsmArch;
-use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
 use rustc_target::spec::{
-    DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+    CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo,
+    StackProtector, Target, TargetTriple, TlsModel,
 };
 
-use std::any::Any;
-use std::env;
-use std::fmt;
-use std::io;
-use std::ops::{Div, Mul};
-use std::path::{Path, PathBuf};
-use std::str::FromStr;
-use std::sync::{atomic::AtomicBool, atomic::Ordering::SeqCst, Arc};
+use crate::code_stats::CodeStats;
+pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
+use crate::config::{
+    self, CoverageLevel, CrateType, ErrorOutputType, FunctionReturn, Input, InstrumentCoverage,
+    OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath,
+};
+use crate::parse::{add_feature_diagnostics, ParseSess};
+use crate::search_paths::{PathKind, SearchPath};
+use crate::{errors, filesearch, lint};
 
 struct OptimizationFuel {
     /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
@@ -952,10 +950,10 @@ fn default_emitter(
         t => t,
     };
     match sopts.error_format {
-        config::ErrorOutputType::HumanReadable(kind) => {
-            let (short, color_config) = kind.unzip();
+        config::ErrorOutputType::HumanReadable(kind, color_config) => {
+            let short = kind.short();
 
-            if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
+            if let HumanReadableErrorType::AnnotateSnippet = kind {
                 let emitter = AnnotateSnippetEmitter::new(
                     Some(source_map),
                     bundle,
@@ -980,13 +978,14 @@ fn default_emitter(
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
         }
-        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(
+        config::ErrorOutputType::Json { pretty, json_rendered, color_config } => Box::new(
             JsonEmitter::new(
                 Box::new(io::BufWriter::new(io::stderr())),
                 source_map,
                 fallback_bundle,
                 pretty,
                 json_rendered,
+                color_config,
             )
             .registry(Some(registry))
             .fluent_bundle(bundle)
@@ -1427,20 +1426,23 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
     let fallback_bundle =
         fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
     let emitter: Box<DynEmitter> = match output {
-        config::ErrorOutputType::HumanReadable(kind) => {
-            let (short, color_config) = kind.unzip();
+        config::ErrorOutputType::HumanReadable(kind, color_config) => {
+            let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
                     .short_message(short),
             )
         }
-        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::new(
-            Box::new(io::BufWriter::new(io::stderr())),
-            Lrc::new(SourceMap::new(FilePathMapping::empty())),
-            fallback_bundle,
-            pretty,
-            json_rendered,
-        )),
+        config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
+            Box::new(JsonEmitter::new(
+                Box::new(io::BufWriter::new(io::stderr())),
+                Lrc::new(SourceMap::new(FilePathMapping::empty())),
+                fallback_bundle,
+                pretty,
+                json_rendered,
+                color_config,
+            ))
+        }
     };
     emitter
 }
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index f70a53eeb41..37528a4425f 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,11 +1,11 @@
-use crate::session::Session;
+use std::path::{Path, PathBuf};
+use std::sync::OnceLock;
+
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use rustc_fs_util::try_canonicalize;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use std::{
-    path::{Path, PathBuf},
-    sync::OnceLock,
-};
+
+use crate::session::Session;
 
 impl Session {
     pub fn timer(&self, what: &'static str) -> VerboseTimingGuard<'_> {
diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs
index e244c77f7f9..79f97fd327a 100644
--- a/compiler/rustc_session/src/version.rs
+++ b/compiler/rustc_session/src/version.rs
@@ -1,10 +1,8 @@
-use rustc_macros::{current_rustc_version, Decodable, Encodable, HashStable_Generic};
-use std::{
-    borrow::Cow,
-    fmt::{self, Display},
-};
+use std::borrow::Cow;
+use std::fmt::{self, Display};
 
 use rustc_errors::IntoDiagArg;
+use rustc_macros::{current_rustc_version, Decodable, Encodable, HashStable_Generic};
 
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(HashStable_Generic)]
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 854295dc048..a4577461094 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -5,7 +5,6 @@
 
 // Prefer importing stable_mir over internal rustc constructs to make this file more readable.
 
-use crate::rustc_smir::Tables;
 use rustc_middle::ty::{self as rustc_ty, Const as InternalConst, Ty as InternalTy, TyCtxt};
 use rustc_span::Symbol;
 use stable_mir::abi::Layout;
@@ -21,6 +20,7 @@ use stable_mir::ty::{
 use stable_mir::{CrateItem, CrateNum, DefId};
 
 use super::RustcInternal;
+use crate::rustc_smir::Tables;
 
 impl RustcInternal for CrateItem {
     type T<'tcx> = rustc_span::def_id::DefId;
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 810ffc142a0..e997ea25ec8 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,7 +3,11 @@
 //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
 //! until stable MIR is complete.
 
-use crate::rustc_smir::{context::TablesWrapper, Stable, Tables};
+use std::cell::{Cell, RefCell};
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::ops::Index;
+
 use rustc_data_structures::fx;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::interpret::AllocId;
@@ -15,11 +19,9 @@ use scoped_tls::scoped_thread_local;
 use stable_mir::abi::Layout;
 use stable_mir::ty::IndexedVal;
 use stable_mir::Error;
-use std::cell::Cell;
-use std::cell::RefCell;
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::ops::Index;
+
+use crate::rustc_smir::context::TablesWrapper;
+use crate::rustc_smir::{Stable, Tables};
 
 mod internal;
 pub mod pretty;
diff --git a/compiler/rustc_smir/src/rustc_internal/pretty.rs b/compiler/rustc_smir/src/rustc_internal/pretty.rs
index c0dce08b0d3..b752ad71ecc 100644
--- a/compiler/rustc_smir/src/rustc_internal/pretty.rs
+++ b/compiler/rustc_smir/src/rustc_internal/pretty.rs
@@ -1,8 +1,9 @@
 use std::io;
 
-use super::run;
 use rustc_middle::ty::TyCtxt;
 
+use super::run;
+
 pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()> {
     writeln!(
         w,
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 5d02e3d6e92..0519722e4be 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -1,12 +1,10 @@
-use rustc_middle::mir::{
-    interpret::{alloc_range, AllocRange, Pointer},
-    ConstValue,
-};
+use rustc_middle::mir::interpret::{alloc_range, AllocRange, Pointer};
+use rustc_middle::mir::ConstValue;
+use stable_mir::mir::Mutability;
+use stable_mir::ty::{Allocation, ProvenanceMap};
 use stable_mir::Error;
 
 use crate::rustc_smir::{Stable, Tables};
-use stable_mir::mir::Mutability;
-use stable_mir::ty::{Allocation, ProvenanceMap};
 
 /// Creates new empty `Allocation` from given `Align`.
 fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation {
diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs
index 09866515a2a..883ab7c18b4 100644
--- a/compiler/rustc_smir/src/rustc_smir/builder.rs
+++ b/compiler/rustc_smir/src/rustc_smir/builder.rs
@@ -4,12 +4,13 @@
 //! monomorphic body using internal representation.
 //! After that, we convert the internal representation into a stable one.
 
-use crate::rustc_smir::{Stable, Tables};
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::ty::{self, TyCtxt};
 
+use crate::rustc_smir::{Stable, Tables};
+
 /// Builds a monomorphic body for a given instance.
 pub struct BodyBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index b0ced8e920f..f9663f2dd30 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -5,6 +5,9 @@
 
 #![allow(rustc::usage_of_qualified_ty)]
 
+use std::cell::RefCell;
+use std::iter;
+
 use rustc_abi::HasDataLayout;
 use rustc_hir::LangItem;
 use rustc_middle::ty::layout::{
@@ -28,8 +31,6 @@ use stable_mir::ty::{
     TyConst, TyKind, UintTy, VariantDef,
 };
 use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
-use std::cell::RefCell;
-use std::iter;
 
 use crate::rustc_internal::RustcInternal;
 use crate::rustc_smir::builder::BodyBuilder;
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index cbc3aae1703..9f554ec6c35 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -2,7 +2,6 @@
 
 #![allow(rustc::usage_of_qualified_ty)]
 
-use crate::rustc_smir::{Stable, Tables};
 use rustc_middle::ty;
 use rustc_target::abi::call::Conv;
 use stable_mir::abi::{
@@ -14,6 +13,8 @@ use stable_mir::opaque;
 use stable_mir::target::MachineSize as Size;
 use stable_mir::ty::{Align, IndexedVal, VariantIdx};
 
+use crate::rustc_smir::{Stable, Tables};
+
 impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
     type T = VariantIdx;
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/error.rs b/compiler/rustc_smir/src/rustc_smir/convert/error.rs
index 3d689708915..82ecfa630dd 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/error.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/error.rs
@@ -2,10 +2,11 @@
 //!
 //! Currently we encode everything as [stable_mir::Error], which is represented as a string.
 
-use crate::rustc_smir::{Stable, Tables};
 use rustc_middle::mir::interpret::AllocError;
 use rustc_middle::ty::layout::LayoutError;
 
+use crate::rustc_smir::{Stable, Tables};
+
 impl<'tcx> Stable<'tcx> for LayoutError<'tcx> {
     type T = stable_mir::Error;
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 8bfaa112c2f..da705e6f959 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -1,9 +1,8 @@
 //! Conversion of internal Rust compiler `mir` items to stable ones.
 
-use rustc_middle::bug;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::alloc_range;
 use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::{bug, mir};
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment};
 use stable_mir::ty::{Allocation, ConstantKind, MirConst};
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 82522e995d6..41e9698242b 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,6 +7,8 @@
 //!
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
+use std::ops::RangeInclusive;
+
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::AllocId;
@@ -16,7 +18,6 @@ use stable_mir::abi::Layout;
 use stable_mir::mir::mono::InstanceDef;
 use stable_mir::ty::{MirConstId, Span, TyConstId};
 use stable_mir::{CtorKind, ItemKind};
-use std::ops::RangeInclusive;
 use tracing::debug;
 
 use crate::rustc_internal::IndexMap;
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 4c7029c4e52..26aa782e5d7 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -1,7 +1,9 @@
+use std::ops::Range;
+
+use rustc_data_structures::sync::Lrc;
+
 use crate::source_map::SourceMap;
 use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData};
-use rustc_data_structures::sync::Lrc;
-use std::ops::Range;
 
 #[derive(Clone)]
 struct CacheEntry {
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 5456303b36f..a45b676acae 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -1,4 +1,6 @@
-use crate::{HashStableContext, SpanDecoder, SpanEncoder, Symbol};
+use std::fmt;
+use std::hash::{BuildHasherDefault, Hash, Hasher};
+
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{
     Hash64, HashStable, StableHasher, StableOrd, ToStableHashKey,
@@ -8,8 +10,8 @@ use rustc_data_structures::AtomicRef;
 use rustc_index::Idx;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Encodable};
-use std::fmt;
-use std::hash::{BuildHasherDefault, Hash, Hasher};
+
+use crate::{HashStableContext, SpanDecoder, SpanEncoder, Symbol};
 
 pub type StableCrateIdMap =
     indexmap::IndexMap<StableCrateId, CrateNum, BuildHasherDefault<Unhasher>>;
diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs
index 87a0ccbb1a5..4f120db48f0 100644
--- a/compiler/rustc_span/src/edit_distance.rs
+++ b/compiler/rustc_span/src/edit_distance.rs
@@ -9,9 +9,10 @@
 // algorithm should not matter to the caller of the methods, which is why it is not noted in the
 // documentation.
 
-use crate::symbol::Symbol;
 use std::{cmp, mem};
 
+use crate::symbol::Symbol;
+
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 483e32c6453..434df35a515 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -24,10 +24,11 @@
 // because getting it wrong can lead to nested `HygieneData::with` calls that
 // trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
 
-use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
-use crate::edition::Edition;
-use crate::symbol::{kw, sym, Symbol};
-use crate::{with_session_globals, HashStableContext, Span, SpanDecoder, SpanEncoder, DUMMY_SP};
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+use std::fmt;
+use std::hash::Hash;
+
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher};
@@ -36,12 +37,13 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::cell::RefCell;
-use std::collections::hash_map::Entry;
-use std::fmt;
-use std::hash::Hash;
 use tracing::{debug, trace};
 
+use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
+use crate::edition::Edition;
+use crate::symbol::{kw, sym, Symbol};
+use crate::{with_session_globals, HashStableContext, Span, SpanDecoder, SpanEncoder, DUMMY_SP};
+
 /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct SyntaxContext(u32);
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index b94f910d4bc..35fe28c5d42 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -47,15 +47,17 @@ use tracing::debug;
 
 mod caching_source_map_view;
 pub mod source_map;
-pub use self::caching_source_map_view::CachingSourceMapView;
 use source_map::{SourceMap, SourceMapInputs};
 
+pub use self::caching_source_map_view::CachingSourceMapView;
+
 pub mod edition;
 use edition::Edition;
 pub mod hygiene;
 use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
-pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
+pub use hygiene::{
+    DesugaringKind, ExpnData, ExpnHash, ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext,
+};
 use rustc_data_structures::stable_hasher::HashingControls;
 pub mod def_id;
 use def_id::{CrateNum, DefId, DefIndex, DefPathHash, LocalDefId, StableCrateId, LOCAL_CRATE};
@@ -71,10 +73,6 @@ pub mod fatal_error;
 
 pub mod profiling;
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
-use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
-
 use std::borrow::Cow;
 use std::cmp::{self, Ordering};
 use std::hash::Hash;
@@ -83,8 +81,10 @@ use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, iter};
 
-use md5::Digest;
-use md5::Md5;
+use md5::{Digest, Md5};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
+use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
 use sha1::Sha1;
 use sha2::Sha256;
 
diff --git a/compiler/rustc_span/src/profiling.rs b/compiler/rustc_span/src/profiling.rs
index 66e5369da3a..c5a8bd3b15b 100644
--- a/compiler/rustc_span/src/profiling.rs
+++ b/compiler/rustc_span/src/profiling.rs
@@ -1,9 +1,9 @@
-use crate::source_map::SourceMap;
-
 use std::borrow::Borrow;
 
 use rustc_data_structures::profiling::EventArgRecorder;
 
+use crate::source_map::SourceMap;
+
 /// Extension trait for self-profiling purposes: allows to record spans within a generic activity's
 /// event arguments.
 pub trait SpannedEventArgRecorder {
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 14c157a0111..f914e8dc1ba 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -9,15 +9,16 @@
 //! within the `SourceMap`, which upon request can be converted to line and column
 //! information, source code snippets, etc.
 
-use crate::*;
+use std::io::{self, BorrowedBuf, Read};
+use std::{fs, path};
+
 use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, RwLock};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_macros::{Decodable, Encodable};
-use std::fs;
-use std::io::{self, BorrowedBuf, Read};
-use std::path;
 use tracing::{debug, instrument, trace};
 
+use crate::*;
+
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index 53d7b7511a6..8988becb171 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -1,14 +1,12 @@
-use crate::def_id::{DefIndex, LocalDefId};
-use crate::hygiene::SyntaxContext;
-use crate::SPAN_TRACK;
-use crate::{BytePos, SpanData};
-
 use rustc_data_structures::fx::FxIndexSet;
-
 // 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;
 
+use crate::def_id::{DefIndex, LocalDefId};
+use crate::hygiene::SyntaxContext;
+use crate::{BytePos, SpanData, SPAN_TRACK};
+
 /// A compressed span.
 ///
 /// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` only
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cfd263d5951..9cb729ec485 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2,6 +2,9 @@
 //! allows bidirectional lookup; i.e., given a value, one can easily find the
 //! type, and vice versa.
 
+use std::hash::{Hash, Hasher};
+use std::{fmt, str};
+
 use rustc_arena::DroplessArena;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::stable_hasher::{
@@ -10,10 +13,6 @@ use rustc_data_structures::stable_hasher::{
 use rustc_data_structures::sync::Lock;
 use rustc_macros::{symbols, Decodable, Encodable, HashStable_Generic};
 
-use std::fmt;
-use std::hash::{Hash, Hasher};
-use std::str;
-
 use crate::{with_session_globals, Edition, Span, DUMMY_SP};
 
 #[cfg(test)]
@@ -277,6 +276,7 @@ symbols! {
         Path,
         PathBuf,
         Pending,
+        PinCoerceUnsized,
         Pointer,
         Poll,
         ProcMacro,
@@ -1217,6 +1217,7 @@ symbols! {
         mir_static_mut,
         mir_storage_dead,
         mir_storage_live,
+        mir_tail_call,
         mir_unreachable,
         mir_unwind_cleanup,
         mir_unwind_continue,
@@ -1618,6 +1619,7 @@ symbols! {
         rustc_dirty,
         rustc_do_not_const_check,
         rustc_doc_primitive,
+        rustc_driver,
         rustc_dummy,
         rustc_dump_def_parents,
         rustc_dump_item_bounds,
@@ -1702,9 +1704,11 @@ symbols! {
         saturating_add,
         saturating_div,
         saturating_sub,
+        select_unpredictable,
         self_in_typedefs,
         self_struct_ctor,
         semitransparent,
+        sha512_sm_x86,
         shadow_call_stack,
         shl,
         shl_assign,
@@ -2446,13 +2450,11 @@ pub mod kw {
 /// Given that `sym` is imported, use them like `sym::symbol_name`.
 /// For example `sym::rustfmt` or `sym::u8`.
 pub mod sym {
-    use super::Symbol;
-
-    #[doc(inline)]
-    pub use super::sym_generated::*;
-
     // Used from a macro in `librustc_feature/accepted.rs`
     pub use super::kw::MacroRules as macro_rules;
+    #[doc(inline)]
+    pub use super::sym_generated::*;
+    use super::Symbol;
 
     /// Get the symbol for an integer.
     ///
diff --git a/compiler/rustc_span/src/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs
index 4366c5a2c26..c6aa7627b2b 100644
--- a/compiler/rustc_span/src/symbol/tests.rs
+++ b/compiler/rustc_span/src/symbol/tests.rs
@@ -1,5 +1,4 @@
 use super::*;
-
 use crate::create_default_session_globals_then;
 
 #[test]
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
index 9b87a1419fa..775f3112ed5 100644
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ b/compiler/rustc_symbol_mangling/src/errors.rs
@@ -1,8 +1,9 @@
 //! Errors emitted by symbol_mangling.
 
+use std::fmt;
+
 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
 use rustc_span::Span;
-use std::fmt;
 
 pub struct TestOutput {
     pub span: Span,
diff --git a/compiler/rustc_symbol_mangling/src/hashed.rs b/compiler/rustc_symbol_mangling/src/hashed.rs
index d4cd6161ac0..8e2f94991cf 100644
--- a/compiler/rustc_symbol_mangling/src/hashed.rs
+++ b/compiler/rustc_symbol_mangling/src/hashed.rs
@@ -1,9 +1,10 @@
-use crate::v0;
+use std::fmt::Write;
+
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::ty::{Instance, TyCtxt};
 
-use std::fmt::Write;
+use crate::v0;
 
 pub(super) fn mangle<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 5aa46cc0dea..0f91684a3a4 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -1,12 +1,14 @@
+use std::fmt::{self, Write};
+use std::mem::{self, discriminant};
+
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::bug;
 use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
-use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, GenericArgKind};
-use std::fmt::{self, Write};
-use std::mem::{self, discriminant};
+use rustc_middle::ty::{
+    self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
+};
 use tracing::debug;
 
 pub(super) fn mangle<'tcx>(
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index e65d3080a0a..dea4eb08c76 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -97,8 +97,7 @@
 
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
+use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Instance, TyCtxt};
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index f0fb87fe83c..774d0b5a612 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -4,12 +4,13 @@
 //! def-path. This is used for unit testing the code that generates
 //! paths etc in all kinds of annoying scenarios.
 
-use crate::errors::{Kind, TestOutput};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{GenericArgs, Instance, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 
+use crate::errors::{Kind, TestOutput};
+
 const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
 const DEF_PATH: Symbol = sym::rustc_def_path;
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 5f8029af020..c2451c08d11 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,3 +1,7 @@
+use std::fmt::Write;
+use std::iter;
+use std::ops::Range;
+
 use rustc_data_structures::base_n::ToBaseN;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::intern::Interned;
@@ -9,18 +13,13 @@ use rustc_middle::bug;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, PrintError, Printer};
 use rustc_middle::ty::{
-    self, EarlyBinder, FloatTy, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable,
-    TypeVisitableExt, UintTy,
+    self, EarlyBinder, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty,
+    TyCtxt, TypeVisitable, TypeVisitableExt, UintTy,
 };
-use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::kw;
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
-use std::fmt::Write;
-use std::iter;
-use std::ops::Range;
-
 pub(super) fn mangle<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 2cb8ac7e8bf..c7d24154e8b 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -22,5 +22,5 @@ tracing = "0.1"
 # tidy-alphabetical-start
 default-features = false
 features = ["elf", "macho"]
-version = "0.32.0"
+version = "0.36.2"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 9f13c195e4c..5bfc528dffc 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -1,11 +1,12 @@
-use crate::abi::{self, Abi, Align, FieldsShape, Size};
-use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
-use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
-use rustc_macros::HashStable_Generic;
-use rustc_span::Symbol;
 use std::fmt;
 use std::str::FromStr;
 
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+
+use crate::abi::{self, Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
+
 mod aarch64;
 mod amdgpu;
 mod arm;
@@ -237,8 +238,10 @@ impl Reg {
                 _ => panic!("unsupported integer: {self:?}"),
             },
             RegKind::Float => match self.size.bits() {
+                16 => dl.f16_align.abi,
                 32 => dl.f32_align.abi,
                 64 => dl.f64_align.abi,
+                128 => dl.f128_align.abi,
                 _ => panic!("unsupported float: {self:?}"),
             },
             RegKind::Vector => dl.vector_align(self.size).abi,
@@ -967,8 +970,9 @@ impl FromStr for Conv {
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(ArgAbi<'_, usize>, 56);
     static_assert_size!(FnAbi<'_, usize>, 80);
diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs
index ac68e8879f6..27d197af792 100644
--- a/compiler/rustc_target/src/abi/call/nvptx64.rs
+++ b/compiler/rustc_target/src/abi/call/nvptx64.rs
@@ -1,8 +1,7 @@
+use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
 use crate::abi::call::{ArgAbi, FnAbi, PassMode, Reg, Size, Uniform};
 use crate::abi::{HasDataLayout, TyAbiInterface};
 
-use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
-
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
     if ret.layout.is_aggregate() && ret.layout.is_sized() {
         classify_aggregate(ret)
diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs
index 11a6cb52bab..749eea0ef63 100644
--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
+++ b/compiler/rustc_target/src/abi/call/powerpc64.rs
@@ -41,64 +41,23 @@ where
     })
 }
 
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi: ABI)
+fn classify<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI, is_ret: bool)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout,
 {
-    if !ret.layout.is_sized() {
+    if arg.is_ignore() || !arg.layout.is_sized() {
         // Not touching this...
         return;
     }
-    if !ret.layout.is_aggregate() {
-        ret.extend_integer_width_to(64);
+    if !arg.layout.is_aggregate() {
+        arg.extend_integer_width_to(64);
         return;
     }
 
     // The ELFv1 ABI doesn't return aggregates in registers
-    if abi == ELFv1 {
-        ret.make_indirect();
-        return;
-    }
-
-    if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
-        ret.cast_to(uniform);
-        return;
-    }
-
-    let size = ret.layout.size;
-    let bits = size.bits();
-    if bits <= 128 {
-        let unit = if cx.data_layout().endian == Endian::Big {
-            Reg { kind: RegKind::Integer, size }
-        } else if bits <= 8 {
-            Reg::i8()
-        } else if bits <= 16 {
-            Reg::i16()
-        } else if bits <= 32 {
-            Reg::i32()
-        } else {
-            Reg::i64()
-        };
-
-        ret.cast_to(Uniform::new(unit, size));
-        return;
-    }
-
-    ret.make_indirect();
-}
-
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI)
-where
-    Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
-{
-    if !arg.layout.is_sized() {
-        // Not touching this...
-        return;
-    }
-    if !arg.layout.is_aggregate() {
-        arg.extend_integer_width_to(64);
+    if is_ret && abi == ELFv1 {
+        arg.make_indirect();
         return;
     }
 
@@ -108,7 +67,10 @@ where
     }
 
     let size = arg.layout.size;
-    if size.bits() <= 64 {
+    if is_ret && size.bits() > 128 {
+        // Non-homogeneous aggregates larger than two doublewords are returned indirectly.
+        arg.make_indirect();
+    } else if size.bits() <= 64 {
         // Aggregates smaller than a doubleword should appear in
         // the least-significant bits of the parameter doubleword.
         arg.cast_to(Reg { kind: RegKind::Integer, size })
@@ -138,14 +100,9 @@ where
         }
     };
 
-    if !fn_abi.ret.is_ignore() {
-        classify_ret(cx, &mut fn_abi.ret, abi);
-    }
+    classify(cx, &mut fn_abi.ret, abi, true);
 
     for arg in fn_abi.args.iter_mut() {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(cx, arg, abi);
+        classify(cx, arg, abi, false);
     }
 }
diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs
index 90de1a42bc0..4e19460bd28 100644
--- a/compiler/rustc_target/src/abi/call/x86_win64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_win64.rs
@@ -1,5 +1,5 @@
 use crate::abi::call::{ArgAbi, FnAbi, Reg};
-use crate::abi::Abi;
+use crate::abi::{Abi, Float, Primitive};
 
 // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
 
@@ -18,8 +18,12 @@ pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
                 // FIXME(eddyb) there should be a size cap here
                 // (probably what clang calls "illegal vectors").
             }
-            Abi::Scalar(_) => {
-                if a.layout.size.bytes() > 8 {
+            Abi::Scalar(scalar) => {
+                // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
+                // with what LLVM expects.
+                if a.layout.size.bytes() > 8
+                    && !matches!(scalar.primitive(), Primitive::Float(Float::F128))
+                {
                     a.make_indirect();
                 } else {
                     a.extend_integer_width_to(32);
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 737e9a8eab0..9bd0aff1d3b 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1,15 +1,14 @@
+use std::fmt;
+use std::ops::Deref;
+
 use rustc_data_structures::intern::Interned;
+use rustc_macros::HashStable_Generic;
 pub use Float::*;
 pub use Integer::*;
 pub use Primitive::*;
 
 use crate::json::{Json, ToJson};
 
-use std::fmt;
-use std::ops::Deref;
-
-use rustc_macros::HashStable_Generic;
-
 pub mod call;
 
 // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 1a3218da1af..358efb4174d 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,8 +1,10 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use crate::spec::{RelocModel, Target};
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_span::Symbol;
-use std::fmt;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+use crate::spec::{RelocModel, Target};
 
 def_reg_class! {
     AArch64 AArch64InlineAsmRegClass {
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index 70fcaab1847..f8d0d40e8a7 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -1,8 +1,10 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use crate::spec::{RelocModel, Target};
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_span::{sym, Symbol};
-use std::fmt;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+use crate::spec::{RelocModel, Target};
 
 def_reg_class! {
     Arm ArmInlineAsmRegClass {
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
index 6943fd9b5d7..276f376b297 100644
--- a/compiler/rustc_target/src/asm/avr.rs
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Avr AvrInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
index faaeabb3c90..500fb4173e4 100644
--- a/compiler/rustc_target/src/asm/bpf.rs
+++ b/compiler/rustc_target/src/asm/bpf.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Bpf BpfInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs
index db6cdecfe19..a4913ed76ab 100644
--- a/compiler/rustc_target/src/asm/csky.rs
+++ b/compiler/rustc_target/src/asm/csky.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     CSKY CSKYInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index 7a809efee6f..f7e726c3376 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Hexagon HexagonInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
index 534b696f7ed..b1c01d27cad 100644
--- a/compiler/rustc_target/src/asm/loongarch.rs
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     LoongArch LoongArchInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/m68k.rs b/compiler/rustc_target/src/asm/m68k.rs
index ea367e3d2f9..680404bf355 100644
--- a/compiler/rustc_target/src/asm/m68k.rs
+++ b/compiler/rustc_target/src/asm/m68k.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     M68k M68kInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index f0d659c9b97..e28b8453b47 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Mips MipsInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index b057bf94a08..4d8c5cea8a8 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -1,10 +1,12 @@
-use crate::spec::Target;
-use crate::{abi::Size, spec::RelocModel};
+use std::fmt;
+use std::str::FromStr;
+
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::Symbol;
-use std::fmt;
-use std::str::FromStr;
+
+use crate::abi::Size;
+use crate::spec::{RelocModel, Target};
 
 pub struct ModifierInfo {
     pub modifier: char,
diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs
index 14013cd8a7b..5ed2023e384 100644
--- a/compiler/rustc_target/src/asm/msp430.rs
+++ b/compiler/rustc_target/src/asm/msp430.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Msp430 Msp430InlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs
index 6c066ad7ac8..da8b79d8935 100644
--- a/compiler/rustc_target/src/asm/nvptx.rs
+++ b/compiler/rustc_target/src/asm/nvptx.rs
@@ -1,6 +1,7 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_span::Symbol;
 
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Nvptx NvptxInlineAsmRegClass {
         reg16,
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index 45e9ace0f29..b2416466132 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     PowerPC PowerPCInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index 02a4a5e2ece..2b9d6114930 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -1,8 +1,10 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use crate::spec::{RelocModel, Target};
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_span::{sym, Symbol};
-use std::fmt;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+use crate::spec::{RelocModel, Target};
 
 def_reg_class! {
     RiscV RiscVInlineAsmRegClass {
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index 2bab41cd8a1..4258b23ac57 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -1,7 +1,9 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use rustc_span::Symbol;
 use std::fmt;
 
+use rustc_span::Symbol;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     S390x S390xInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs
index f242faec026..c050c4e36b7 100644
--- a/compiler/rustc_target/src/asm/spirv.rs
+++ b/compiler/rustc_target/src/asm/spirv.rs
@@ -1,6 +1,7 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_span::Symbol;
 
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     SpirV SpirVInlineAsmRegClass {
         reg,
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
index b5f4d10fb2b..0fbfa527bc4 100644
--- a/compiler/rustc_target/src/asm/wasm.rs
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -1,6 +1,7 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_span::Symbol;
 
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+
 def_reg_class! {
     Wasm WasmInlineAsmRegClass {
         local,
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 8452961c17c..15c1925bcda 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -1,8 +1,10 @@
-use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
-use crate::spec::{RelocModel, Target};
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_span::Symbol;
-use std::fmt;
+
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
+use crate::spec::{RelocModel, Target};
 
 def_reg_class! {
     X86 X86InlineAsmRegClass {
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index ecc91ab9a31..b2116c51216 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -9,12 +9,12 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![feature(min_exhaustive_patterns)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_target/src/spec/abi/tests.rs b/compiler/rustc_target/src/spec/abi/tests.rs
index 251a12fe7aa..4823058dd69 100644
--- a/compiler/rustc_target/src/spec/abi/tests.rs
+++ b/compiler/rustc_target/src/spec/abi/tests.rs
@@ -1,3 +1,5 @@
+use std::assert_matches::assert_matches;
+
 use super::*;
 
 #[allow(non_snake_case)]
@@ -16,7 +18,7 @@ fn lookup_cdecl() {
 #[test]
 fn lookup_baz() {
     let abi = lookup("baz");
-    assert!(matches!(abi, Err(AbiUnsupported::Unrecognized)))
+    assert_matches!(abi, Err(AbiUnsupported::Unrecognized));
 }
 
 #[test]
diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs
index 05542009083..39d7cf7d097 100644
--- a/compiler/rustc_target/src/spec/base/apple/mod.rs
+++ b/compiler/rustc_target/src/spec/base/apple/mod.rs
@@ -1,8 +1,10 @@
-use std::{borrow::Cow, env};
+use std::borrow::Cow;
+use std::env;
 
-use crate::spec::{add_link_args, add_link_args_iter};
-use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs, LinkerFlavor, Lld};
-use crate::spec::{SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions};
+use crate::spec::{
+    add_link_args, add_link_args_iter, cvs, Cc, DebuginfoKind, FramePointer, LinkArgs,
+    LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions,
+};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr_gnu.rs
index 211d52f5b07..c3d0344ea6c 100644
--- a/compiler/rustc_target/src/spec/base/avr_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/avr_gnu.rs
@@ -1,6 +1,7 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
 use object::elf;
 
+use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
+
 /// A base target for AVR devices using the GNU toolchain.
 ///
 /// Requires GNU avr-gcc and avr-binutils on the host system.
diff --git a/compiler/rustc_target/src/spec/base/linux.rs b/compiler/rustc_target/src/spec/base/linux.rs
index df8e848124a..34b2eb0f641 100644
--- a/compiler/rustc_target/src/spec/base/linux.rs
+++ b/compiler/rustc_target/src/spec/base/linux.rs
@@ -1,6 +1,7 @@
-use crate::spec::{cvs, RelroLevel, SplitDebuginfo, TargetOptions};
 use std::borrow::Cow;
 
+use crate::spec::{cvs, RelroLevel, SplitDebuginfo, TargetOptions};
+
 pub fn opts() -> TargetOptions {
     TargetOptions {
         os: "linux".into(),
diff --git a/compiler/rustc_target/src/spec/base/linux_musl.rs b/compiler/rustc_target/src/spec/base/linux_musl.rs
index 5117cadbee0..42aa1e1a6da 100644
--- a/compiler/rustc_target/src/spec/base/linux_musl.rs
+++ b/compiler/rustc_target/src/spec/base/linux_musl.rs
@@ -1,5 +1,4 @@
-use crate::spec::crt_objects;
-use crate::spec::{base, LinkSelfContainedDefault, TargetOptions};
+use crate::spec::{base, crt_objects, LinkSelfContainedDefault, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut base = base::linux::opts();
diff --git a/compiler/rustc_target/src/spec/base/msvc.rs b/compiler/rustc_target/src/spec/base/msvc.rs
index 44fc376fea0..720cf03005a 100644
--- a/compiler/rustc_target/src/spec/base/msvc.rs
+++ b/compiler/rustc_target/src/spec/base/msvc.rs
@@ -1,6 +1,7 @@
-use crate::spec::{DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
 use std::borrow::Cow;
 
+use crate::spec::{DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
+
 pub fn opts() -> TargetOptions {
     // Suppress the verbose logo and authorship debugging output, which would needlessly
     // clog any log files.
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index 1357de2dad1..7346e42dd91 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -1,8 +1,10 @@
-use crate::spec::LinkSelfContainedDefault;
-use crate::spec::{add_link_args, crt_objects};
-use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
 use std::borrow::Cow;
 
+use crate::spec::{
+    add_link_args, crt_objects, cvs, Cc, DebuginfoKind, LinkSelfContainedDefault, LinkerFlavor,
+    Lld, SplitDebuginfo, TargetOptions,
+};
+
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = TargetOptions::link_args(
         LinkerFlavor::Gnu(Cc::No, Lld::No),
diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
index b1d8e2be5a6..88c3b8a81ad 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
@@ -1,6 +1,7 @@
-use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
 use std::borrow::Cow;
 
+use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
+
 pub fn opts() -> TargetOptions {
     // We cannot use `-nodefaultlibs` because compiler-rt has to be passed
     // as a path since it's not added to linker search path by the default.
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index 53f710b8f9e..e3b6430a463 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -40,10 +40,11 @@
 //! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
 //! when linking in self-contained mode.
 
-use crate::spec::LinkOutputKind;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 
+use crate::spec::LinkOutputKind;
+
 pub type CrtObjects = BTreeMap<LinkOutputKind, Vec<Cow<'static, str>>>;
 
 pub(super) fn new(obj_table: &[(LinkOutputKind, &[&'static str])]) -> CrtObjects {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0efe68252af..8ce51ba2463 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -34,16 +34,6 @@
 //! the target's settings, though `target-feature` and `link-args` will *add*
 //! to the list specified by the target, rather than replace.
 
-use crate::abi::call::Conv;
-use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
-use crate::json::{Json, ToJson};
-use crate::spec::abi::Abi;
-use crate::spec::crt_objects::CrtObjects;
-use rustc_fs_util::try_canonicalize;
-use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use rustc_span::symbol::{kw, sym, Symbol};
-use serde_json::Value;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::hash::{Hash, Hasher};
@@ -51,15 +41,28 @@ use std::ops::{Deref, DerefMut};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
+
+use rustc_fs_util::try_canonicalize;
+use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use rustc_span::symbol::{kw, sym, Symbol};
+use serde_json::Value;
 use tracing::debug;
 
+use crate::abi::call::Conv;
+use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
+use crate::json::{Json, ToJson};
+use crate::spec::abi::Abi;
+use crate::spec::crt_objects::CrtObjects;
+
 pub mod abi;
 pub mod crt_objects;
 
 mod base;
-pub use base::apple::deployment_target as current_apple_deployment_target;
-pub use base::apple::platform as current_apple_platform;
-pub use base::apple::sdk_version as current_apple_sdk_version;
+pub use base::apple::{
+    deployment_target as current_apple_deployment_target, platform as current_apple_platform,
+    sdk_version as current_apple_sdk_version,
+};
 pub use base::avr_gnu::ef_avr_arch;
 
 /// Linker is called through a C/C++ compiler.
@@ -3146,11 +3149,10 @@ impl Target {
                     if let Some(a) = o.as_array() {
                         for o in a {
                             if let Some(s) = o.as_str() {
-                                let p = s.split('=').collect::<Vec<_>>();
-                                if p.len() == 2 {
-                                    let k = p[0].to_string();
-                                    let v = p[1].to_string();
-                                    base.$key_name.to_mut().push((k.into(), v.into()));
+                                if let [k, v] = *s.split('=').collect::<Vec<_>>() {
+                                    base.$key_name
+                                        .to_mut()
+                                        .push((k.to_string().into(), v.to_string().into()))
                                 }
                             }
                         }
@@ -3353,8 +3355,7 @@ impl Target {
         target_triple: &TargetTriple,
         sysroot: &Path,
     ) -> Result<(Target, TargetWarnings), String> {
-        use std::env;
-        use std::fs;
+        use std::{env, fs};
 
         fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
             let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
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 f37781c3f63..65f2a1e3069 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
         llvm_target: macos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
             description: Some("ARM64 macOS (11.0+, Big Sur+)".into()),
-            tier: Some(2),
+            tier: Some(1),
             host_tools: Some(true),
             std: Some(true),
         },
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 5924e4f5757..726a85c81f3 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
@@ -1,5 +1,4 @@
-use crate::spec::SanitizerSet;
-use crate::spec::{base, StackProbeType, Target, TargetOptions};
+use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = base::linux_ohos::opts();
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 8cddb6fe005..eb223af8cf4 100644
--- a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
@@ -1,5 +1,5 @@
-use crate::spec::Target;
-use crate::{abi::Endian, spec::base};
+use crate::abi::Endian;
+use crate::spec::{base, Target};
 
 pub fn target() -> Target {
     Target {
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 d070aa0ec44..12164adc00f 100644
--- a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
@@ -1,5 +1,5 @@
-use crate::spec::Target;
-use crate::{abi::Endian, spec::base};
+use crate::abi::Endian;
+use crate::spec::{base, Target};
 
 pub fn target() -> Target {
     Target {
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 19b04607f0e..f7a6e0bd857 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: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.3".into()),
-            tier: Some(3),
-            host_tools: Some(false),
-            std: None, // ?
+            description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.5".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_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
index 744ffff721f..c7f47da6972 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
@@ -1,11 +1,12 @@
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
+            description: Some("Freestanding/bare-metal LoongArch64".into()),
             tier: Some(2),
             host_tools: Some(false),
             std: Some(false),
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 a382e7a53fb..21e4f4a2b05 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
@@ -1,11 +1,12 @@
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
+            description: Some("Freestanding/bare-metal LoongArch64 softfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
             std: Some(false),
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 15156fbcfc9..ec5edfb6e42 100644
--- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
@@ -1,5 +1,6 @@
-use crate::spec::LinkSelfContainedDefault;
-use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions};
+use crate::spec::{
+    LinkSelfContainedDefault, LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
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 726778aca0d..8aa5e098890 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
@@ -1,5 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
index 3e575fdd528..8b401329868 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
@@ -21,6 +21,7 @@ pub fn target() -> Target {
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
             supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
+            crt_static_default: false,
             ..base::linux_musl::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
index a75f8969a73..bfd88bd042e 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
@@ -1,6 +1,7 @@
-use crate::spec::SanitizerSet;
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
-use crate::spec::{RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
+    TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
index 6a468227ba6..5bea708e0dd 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
@@ -1,6 +1,7 @@
-use crate::spec::SanitizerSet;
-use crate::spec::{cvs, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
-use crate::spec::{RelocModel, Target, TargetOptions};
+use crate::spec::{
+    cvs, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
+    TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
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 ba9a10e6633..fa3f1eff457 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
@@ -1,5 +1,7 @@
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
-use crate::spec::{RelocModel, SanitizerSet, Target, TargetOptions};
+use crate::spec::{
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
+    TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
index 1e18466c206..215c0724f91 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
@@ -1,6 +1,7 @@
-use crate::spec::SanitizerSet;
-use crate::spec::{cvs, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
-use crate::spec::{RelocModel, Target, TargetOptions};
+use crate::spec::{
+    cvs, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
+    TargetOptions,
+};
 
 pub fn target() -> Target {
     Target {
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 96dd8588d4f..8806f3e87fa 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
@@ -9,8 +9,7 @@
 //! The default link script is very likely wrong, so you should use
 //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
 
-use crate::spec::{base, PanicStrategy, RelocModel, Target, TargetOptions};
-use crate::spec::{cvs, FramePointer};
+use crate::spec::{base, cvs, FramePointer, PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
index a8e7f22c068..29e6dff2068 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
@@ -10,9 +10,7 @@
 //! was since renamed to `wasm32-wasip1` after the preview2 target was
 //! introduced.
 
-use crate::spec::crt_objects;
-use crate::spec::LinkSelfContainedDefault;
-use crate::spec::{base, Cc, LinkerFlavor, Target};
+use crate::spec::{base, crt_objects, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut options = base::wasm::options();
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
index 63d1f4869be..489bae4fedf 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
@@ -16,9 +16,7 @@
 //! You can see more about wasi at <https://wasi.dev> and the component model at
 //! <https://github.com/WebAssembly/component-model>.
 
-use crate::spec::crt_objects;
-use crate::spec::LinkSelfContainedDefault;
-use crate::spec::{base, RelocModel, Target};
+use crate::spec::{base, crt_objects, LinkSelfContainedDefault, RelocModel, Target};
 
 pub fn target() -> Target {
     let mut options = base::wasm::options();
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 94638ae62f8..c3a52a506bc 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
@@ -1,6 +1,5 @@
 use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::X86_64;
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 549706998d4..175a53f237d 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
@@ -4,8 +4,10 @@
 // `target-cpu` compiler flags to opt-in more hardware-specific
 // features.
 
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
-use crate::spec::{RelroLevel, SanitizerSet, StackProbeType, Target, TargetOptions};
+use crate::spec::{
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, SanitizerSet, StackProbeType,
+    Target, TargetOptions,
+};
 
 pub fn target() -> Target {
     let opts = TargetOptions {
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 6da1fcca58c..2933da92fcc 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
@@ -5,10 +5,8 @@
 // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::{
-    abi::call::Conv,
-    spec::{base, Target},
-};
+use crate::abi::call::Conv;
+use crate::spec::{base, Target};
 
 pub fn target() -> Target {
     let mut base = base::uefi_msvc::opts();
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 72cbc1be931..a932d4a3cb4 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
@@ -1,6 +1,5 @@
 use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::X86_64h;
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
index 1b66fdbd2af..f041e791a9b 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
@@ -1,5 +1,6 @@
 use crate::abi::Endian;
-use crate::spec::{base::xtensa, cvs, Target, TargetOptions};
+use crate::spec::base::xtensa;
+use crate::spec::{cvs, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
index bf523716313..05666bd81aa 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
@@ -1,4 +1,5 @@
-use crate::spec::{base::xtensa, Target, TargetOptions};
+use crate::spec::base::xtensa;
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
index ad5fda8a4ae..83ef520551f 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
@@ -1,5 +1,6 @@
 use crate::abi::Endian;
-use crate::spec::{base::xtensa, cvs, Target, TargetOptions};
+use crate::spec::base::xtensa;
+use crate::spec::{cvs, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
index 219b2aa48c1..aa125eb1ba6 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
@@ -1,4 +1,5 @@
-use crate::spec::{base::xtensa, Target, TargetOptions};
+use crate::spec::base::xtensa;
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
index ab1d1df43dd..e18acfccf5f 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
@@ -1,5 +1,6 @@
 use crate::abi::Endian;
-use crate::spec::{base::xtensa, cvs, Target, TargetOptions};
+use crate::spec::base::xtensa;
+use crate::spec::{cvs, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
index 632eef3a584..ecbb51dfb66 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
@@ -1,4 +1,5 @@
-use crate::spec::{base::xtensa, Target, TargetOptions};
+use crate::spec::base::xtensa;
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 3be18ef3127..fc5bd846e02 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -1,6 +1,7 @@
-use super::super::*;
 use std::assert_matches::assert_matches;
 
+use super::super::*;
+
 // Test target self-consistency and JSON encoding/decoding roundtrip.
 pub(super) fn test_target(mut target: Target) {
     let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j);
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 4fb0323b6cf..da66ba270b3 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -1,5 +1,5 @@
-use rustc_span::symbol::sym;
-use rustc_span::symbol::Symbol;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_span::symbol::{sym, Symbol};
 
 /// Features that control behaviour of rustc, rather than the codegen.
 pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
@@ -54,136 +54,154 @@ impl Stability {
 //
 // Stabilizing a target feature requires t-lang approval.
 
-const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+type ImpliedFeatures = &'static [&'static str];
+
+const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("aclass", Unstable(sym::arm_target_feature)),
-    ("aes", Unstable(sym::arm_target_feature)),
-    ("crc", Unstable(sym::arm_target_feature)),
-    ("d32", Unstable(sym::arm_target_feature)),
-    ("dotprod", Unstable(sym::arm_target_feature)),
-    ("dsp", Unstable(sym::arm_target_feature)),
-    ("fp-armv8", Unstable(sym::arm_target_feature)),
-    ("i8mm", Unstable(sym::arm_target_feature)),
-    ("mclass", Unstable(sym::arm_target_feature)),
-    ("neon", Unstable(sym::arm_target_feature)),
-    ("rclass", Unstable(sym::arm_target_feature)),
-    ("sha2", Unstable(sym::arm_target_feature)),
+    ("aclass", Unstable(sym::arm_target_feature), &[]),
+    ("aes", Unstable(sym::arm_target_feature), &["neon"]),
+    ("crc", Unstable(sym::arm_target_feature), &[]),
+    ("d32", Unstable(sym::arm_target_feature), &[]),
+    ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
+    ("dsp", Unstable(sym::arm_target_feature), &[]),
+    ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
+    ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
+    ("mclass", Unstable(sym::arm_target_feature), &[]),
+    ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
+    ("rclass", Unstable(sym::arm_target_feature), &[]),
+    ("sha2", Unstable(sym::arm_target_feature), &["neon"]),
     // This is needed for inline assembly, but shouldn't be stabilized as-is
     // since it should be enabled per-function using #[instruction_set], not
     // #[target_feature].
-    ("thumb-mode", Unstable(sym::arm_target_feature)),
-    ("thumb2", Unstable(sym::arm_target_feature)),
-    ("trustzone", Unstable(sym::arm_target_feature)),
-    ("v5te", Unstable(sym::arm_target_feature)),
-    ("v6", Unstable(sym::arm_target_feature)),
-    ("v6k", Unstable(sym::arm_target_feature)),
-    ("v6t2", Unstable(sym::arm_target_feature)),
-    ("v7", Unstable(sym::arm_target_feature)),
-    ("v8", Unstable(sym::arm_target_feature)),
-    ("vfp2", Unstable(sym::arm_target_feature)),
-    ("vfp3", Unstable(sym::arm_target_feature)),
-    ("vfp4", Unstable(sym::arm_target_feature)),
-    ("virtualization", Unstable(sym::arm_target_feature)),
+    ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
+    ("thumb2", Unstable(sym::arm_target_feature), &[]),
+    ("trustzone", Unstable(sym::arm_target_feature), &[]),
+    ("v5te", Unstable(sym::arm_target_feature), &[]),
+    ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
+    ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
+    ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
+    ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
+    ("v8", Unstable(sym::arm_target_feature), &["v7"]),
+    ("vfp2", Unstable(sym::arm_target_feature), &[]),
+    ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
+    ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
+    ("virtualization", Unstable(sym::arm_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     // FEAT_AES & FEAT_PMULL
-    ("aes", Stable),
+    ("aes", Stable, &["neon"]),
     // FEAT_BF16
-    ("bf16", Stable),
+    ("bf16", Stable, &[]),
     // FEAT_BTI
-    ("bti", Stable),
+    ("bti", Stable, &[]),
     // FEAT_CRC
-    ("crc", Stable),
+    ("crc", Stable, &[]),
     // FEAT_DIT
-    ("dit", Stable),
+    ("dit", Stable, &[]),
     // FEAT_DotProd
-    ("dotprod", Stable),
+    ("dotprod", Stable, &["neon"]),
     // FEAT_DPB
-    ("dpb", Stable),
+    ("dpb", Stable, &[]),
     // FEAT_DPB2
-    ("dpb2", Stable),
+    ("dpb2", Stable, &["dpb"]),
     // FEAT_F32MM
-    ("f32mm", Stable),
+    ("f32mm", Stable, &["sve"]),
     // FEAT_F64MM
-    ("f64mm", Stable),
+    ("f64mm", Stable, &["sve"]),
     // FEAT_FCMA
-    ("fcma", Stable),
+    ("fcma", Stable, &["neon"]),
     // FEAT_FHM
-    ("fhm", Stable),
+    ("fhm", Stable, &["fp16"]),
     // FEAT_FLAGM
-    ("flagm", Stable),
+    ("flagm", Stable, &[]),
     // FEAT_FP16
-    ("fp16", Stable),
+    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
+    ("fp16", Stable, &["neon"]),
     // FEAT_FRINTTS
-    ("frintts", Stable),
+    ("frintts", Stable, &[]),
     // FEAT_I8MM
-    ("i8mm", Stable),
+    ("i8mm", Stable, &[]),
     // FEAT_JSCVT
-    ("jsconv", Stable),
+    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
+    ("jsconv", Stable, &["neon"]),
     // FEAT_LOR
-    ("lor", Stable),
+    ("lor", Stable, &[]),
     // FEAT_LSE
-    ("lse", Stable),
+    ("lse", Stable, &[]),
     // FEAT_MTE & FEAT_MTE2
-    ("mte", Stable),
+    ("mte", Stable, &[]),
     // FEAT_AdvSimd & FEAT_FP
-    ("neon", Stable),
+    ("neon", Stable, &[]),
     // FEAT_PAUTH (address authentication)
-    ("paca", Stable),
+    ("paca", Stable, &[]),
     // FEAT_PAUTH (generic authentication)
-    ("pacg", Stable),
+    ("pacg", Stable, &[]),
     // FEAT_PAN
-    ("pan", Stable),
+    ("pan", Stable, &[]),
     // FEAT_PMUv3
-    ("pmuv3", Stable),
+    ("pmuv3", Stable, &[]),
     // FEAT_RAND
-    ("rand", Stable),
+    ("rand", Stable, &[]),
     // FEAT_RAS & FEAT_RASv1p1
-    ("ras", Stable),
+    ("ras", Stable, &[]),
     // FEAT_RCPC
-    ("rcpc", Stable),
+    ("rcpc", Stable, &[]),
     // FEAT_RCPC2
-    ("rcpc2", Stable),
+    ("rcpc2", Stable, &["rcpc"]),
     // FEAT_RDM
-    ("rdm", Stable),
+    ("rdm", Stable, &["neon"]),
     // FEAT_SB
-    ("sb", Stable),
+    ("sb", Stable, &[]),
     // FEAT_SHA1 & FEAT_SHA256
-    ("sha2", Stable),
+    ("sha2", Stable, &["neon"]),
     // FEAT_SHA512 & FEAT_SHA3
-    ("sha3", Stable),
+    ("sha3", Stable, &["sha2"]),
     // FEAT_SM3 & FEAT_SM4
-    ("sm4", Stable),
+    ("sm4", Stable, &["neon"]),
     // FEAT_SPE
-    ("spe", Stable),
+    ("spe", Stable, &[]),
     // FEAT_SSBS & FEAT_SSBS2
-    ("ssbs", Stable),
+    ("ssbs", Stable, &[]),
     // FEAT_SVE
-    ("sve", Stable),
+    // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
+    //
+    // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
+    // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
+    //
+    // "For backwards compatibility, Neon and VFP are required in the latest architectures."
+    ("sve", Stable, &["neon"]),
     // FEAT_SVE2
-    ("sve2", Stable),
+    ("sve2", Stable, &["sve"]),
     // FEAT_SVE2_AES
-    ("sve2-aes", Stable),
+    ("sve2-aes", Stable, &["sve2", "aes"]),
     // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", Stable),
+    ("sve2-bitperm", Stable, &["sve2"]),
     // FEAT_SVE2_SHA3
-    ("sve2-sha3", Stable),
+    ("sve2-sha3", Stable, &["sve2", "sha3"]),
     // FEAT_SVE2_SM4
-    ("sve2-sm4", Stable),
+    ("sve2-sm4", Stable, &["sve2", "sm4"]),
     // FEAT_TME
-    ("tme", Stable),
-    ("v8.1a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.2a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.3a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.4a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.5a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.6a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.7a", Unstable(sym::aarch64_ver_target_feature)),
+    ("tme", Stable, &[]),
+    (
+        "v8.1a",
+        Unstable(sym::aarch64_ver_target_feature),
+        &["crc", "lse", "rdm", "pan", "lor", "vh"],
+    ),
+    ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
+    (
+        "v8.3a",
+        Unstable(sym::aarch64_ver_target_feature),
+        &["v8.2a", "rcpc", "paca", "pacg", "jsconv"],
+    ),
+    ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
+    ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
+    ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
+    ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &[]),
     // FEAT_VHE
-    ("vh", Stable),
+    ("vh", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
@@ -191,219 +209,223 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
     &["paca", "pacg"], // Together these represent `pauth` in LLVM
 ];
 
-const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("adx", Stable),
-    ("aes", Stable),
-    ("amx-bf16", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-complex", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-fp16", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-int8", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-tile", Unstable(sym::x86_amx_intrinsics)),
-    ("avx", Stable),
-    ("avx2", Stable),
-    ("avx512bf16", Unstable(sym::avx512_target_feature)),
-    ("avx512bitalg", Unstable(sym::avx512_target_feature)),
-    ("avx512bw", Unstable(sym::avx512_target_feature)),
-    ("avx512cd", Unstable(sym::avx512_target_feature)),
-    ("avx512dq", Unstable(sym::avx512_target_feature)),
-    ("avx512f", Unstable(sym::avx512_target_feature)),
-    ("avx512fp16", Unstable(sym::avx512_target_feature)),
-    ("avx512ifma", Unstable(sym::avx512_target_feature)),
-    ("avx512vbmi", Unstable(sym::avx512_target_feature)),
-    ("avx512vbmi2", Unstable(sym::avx512_target_feature)),
-    ("avx512vl", Unstable(sym::avx512_target_feature)),
-    ("avx512vnni", Unstable(sym::avx512_target_feature)),
-    ("avx512vp2intersect", Unstable(sym::avx512_target_feature)),
-    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature)),
-    ("avxifma", Unstable(sym::avx512_target_feature)),
-    ("avxneconvert", Unstable(sym::avx512_target_feature)),
-    ("avxvnni", Unstable(sym::avx512_target_feature)),
-    ("avxvnniint16", Unstable(sym::avx512_target_feature)),
-    ("avxvnniint8", Unstable(sym::avx512_target_feature)),
-    ("bmi1", Stable),
-    ("bmi2", Stable),
-    ("cmpxchg16b", Stable),
-    ("ermsb", Unstable(sym::ermsb_target_feature)),
-    ("f16c", Stable),
-    ("fma", Stable),
-    ("fxsr", Stable),
-    ("gfni", Unstable(sym::avx512_target_feature)),
-    ("lahfsahf", Unstable(sym::lahfsahf_target_feature)),
-    ("lzcnt", Stable),
-    ("movbe", Stable),
-    ("pclmulqdq", Stable),
-    ("popcnt", Stable),
-    ("prfchw", Unstable(sym::prfchw_target_feature)),
-    ("rdrand", Stable),
-    ("rdseed", Stable),
-    ("rtm", Unstable(sym::rtm_target_feature)),
-    ("sha", Stable),
-    ("sse", Stable),
-    ("sse2", Stable),
-    ("sse3", Stable),
-    ("sse4.1", Stable),
-    ("sse4.2", Stable),
-    ("sse4a", Unstable(sym::sse4a_target_feature)),
-    ("ssse3", Stable),
-    ("tbm", Unstable(sym::tbm_target_feature)),
-    ("vaes", Unstable(sym::avx512_target_feature)),
-    ("vpclmulqdq", Unstable(sym::avx512_target_feature)),
-    ("xop", Unstable(sym::xop_target_feature)),
-    ("xsave", Stable),
-    ("xsavec", Stable),
-    ("xsaveopt", Stable),
-    ("xsaves", Stable),
+    ("adx", Stable, &[]),
+    ("aes", Stable, &["sse2"]),
+    ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
+    ("avx", Stable, &["sse4.2"]),
+    ("avx2", Stable, &["avx"]),
+    ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
+    ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
+    ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("bmi1", Stable, &[]),
+    ("bmi2", Stable, &[]),
+    ("cmpxchg16b", Stable, &[]),
+    ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
+    ("f16c", Stable, &["avx"]),
+    ("fma", Stable, &["avx"]),
+    ("fxsr", Stable, &[]),
+    ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
+    ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
+    ("lzcnt", Stable, &[]),
+    ("movbe", Stable, &[]),
+    ("pclmulqdq", Stable, &[]),
+    ("popcnt", Stable, &[]),
+    ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
+    ("rdrand", Stable, &[]),
+    ("rdseed", Stable, &[]),
+    ("rtm", Unstable(sym::rtm_target_feature), &[]),
+    ("sha", Stable, &["sse2"]),
+    ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
+    ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
+    ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
+    ("sse", Stable, &[]),
+    ("sse2", Stable, &["sse"]),
+    ("sse3", Stable, &["sse2"]),
+    ("sse4.1", Stable, &["ssse3"]),
+    ("sse4.2", Stable, &["sse4.1"]),
+    ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
+    ("ssse3", Stable, &["sse3"]),
+    ("tbm", Unstable(sym::tbm_target_feature), &[]),
+    ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
+    ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
+    ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
+    ("xsave", Stable, &[]),
+    ("xsavec", Stable, &["xsave"]),
+    ("xsaveopt", Stable, &["xsave"]),
+    ("xsaves", Stable, &["xsave"]),
     // tidy-alphabetical-end
 ];
 
-const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("hvx", Unstable(sym::hexagon_target_feature)),
-    ("hvx-length128b", Unstable(sym::hexagon_target_feature)),
+    ("hvx", Unstable(sym::hexagon_target_feature), &[]),
+    ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
     // tidy-alphabetical-end
 ];
 
-const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("altivec", Unstable(sym::powerpc_target_feature)),
-    ("power10-vector", Unstable(sym::powerpc_target_feature)),
-    ("power8-altivec", Unstable(sym::powerpc_target_feature)),
-    ("power8-vector", Unstable(sym::powerpc_target_feature)),
-    ("power9-altivec", Unstable(sym::powerpc_target_feature)),
-    ("power9-vector", Unstable(sym::powerpc_target_feature)),
-    ("vsx", Unstable(sym::powerpc_target_feature)),
+    ("altivec", Unstable(sym::powerpc_target_feature), &[]),
+    ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
+    ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
+    ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
+    ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
+    ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
+    ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
     // tidy-alphabetical-end
 ];
 
-const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("fp64", Unstable(sym::mips_target_feature)),
-    ("msa", Unstable(sym::mips_target_feature)),
-    ("virt", Unstable(sym::mips_target_feature)),
+    ("fp64", Unstable(sym::mips_target_feature), &[]),
+    ("msa", Unstable(sym::mips_target_feature), &[]),
+    ("virt", Unstable(sym::mips_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("a", Stable),
-    ("c", Stable),
-    ("d", Unstable(sym::riscv_target_feature)),
-    ("e", Unstable(sym::riscv_target_feature)),
-    ("f", Unstable(sym::riscv_target_feature)),
-    ("m", Stable),
-    ("relax", Unstable(sym::riscv_target_feature)),
-    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)),
-    ("v", Unstable(sym::riscv_target_feature)),
-    ("zba", Stable),
-    ("zbb", Stable),
-    ("zbc", Stable),
-    ("zbkb", Stable),
-    ("zbkc", Stable),
-    ("zbkx", Stable),
-    ("zbs", Stable),
-    ("zdinx", Unstable(sym::riscv_target_feature)),
-    ("zfh", Unstable(sym::riscv_target_feature)),
-    ("zfhmin", Unstable(sym::riscv_target_feature)),
-    ("zfinx", Unstable(sym::riscv_target_feature)),
-    ("zhinx", Unstable(sym::riscv_target_feature)),
-    ("zhinxmin", Unstable(sym::riscv_target_feature)),
-    ("zk", Stable),
-    ("zkn", Stable),
-    ("zknd", Stable),
-    ("zkne", Stable),
-    ("zknh", Stable),
-    ("zkr", Stable),
-    ("zks", Stable),
-    ("zksed", Stable),
-    ("zksh", Stable),
-    ("zkt", Stable),
+    ("a", Stable, &[]),
+    ("c", Stable, &[]),
+    ("d", Unstable(sym::riscv_target_feature), &["f"]),
+    ("e", Unstable(sym::riscv_target_feature), &[]),
+    ("f", Unstable(sym::riscv_target_feature), &[]),
+    ("m", Stable, &[]),
+    ("relax", Unstable(sym::riscv_target_feature), &[]),
+    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
+    ("v", Unstable(sym::riscv_target_feature), &[]),
+    ("zba", Stable, &[]),
+    ("zbb", Stable, &[]),
+    ("zbc", Stable, &[]),
+    ("zbkb", Stable, &[]),
+    ("zbkc", Stable, &[]),
+    ("zbkx", Stable, &[]),
+    ("zbs", Stable, &[]),
+    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
+    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
+    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
+    ("zfinx", Unstable(sym::riscv_target_feature), &[]),
+    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
+    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
+    ("zk", Stable, &["zkn", "zkr", "zkt"]),
+    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
+    ("zknd", Stable, &[]),
+    ("zkne", Stable, &[]),
+    ("zknh", Stable, &[]),
+    ("zkr", Stable, &[]),
+    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
+    ("zksed", Stable, &[]),
+    ("zksh", Stable, &[]),
+    ("zkt", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
-const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("atomics", Unstable(sym::wasm_target_feature)),
-    ("bulk-memory", Stable),
-    ("exception-handling", Unstable(sym::wasm_target_feature)),
-    ("extended-const", Stable),
-    ("multivalue", Unstable(sym::wasm_target_feature)),
-    ("mutable-globals", Stable),
-    ("nontrapping-fptoint", Stable),
-    ("reference-types", Unstable(sym::wasm_target_feature)),
-    ("relaxed-simd", Unstable(sym::wasm_target_feature)),
-    ("sign-ext", Stable),
-    ("simd128", Stable),
+    ("atomics", Unstable(sym::wasm_target_feature), &[]),
+    ("bulk-memory", Stable, &[]),
+    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
+    ("extended-const", Stable, &[]),
+    ("multivalue", Unstable(sym::wasm_target_feature), &[]),
+    ("mutable-globals", Stable, &[]),
+    ("nontrapping-fptoint", Stable, &[]),
+    ("reference-types", Unstable(sym::wasm_target_feature), &[]),
+    ("relaxed-simd", Stable, &["simd128"]),
+    ("sign-ext", Stable, &[]),
+    ("simd128", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
-const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
+const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
+    &[("alu32", Unstable(sym::bpf_target_feature), &[])];
 
-const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const CSKY_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("10e60", Unstable(sym::csky_target_feature)),
-    ("2e3", Unstable(sym::csky_target_feature)),
-    ("3e3r1", Unstable(sym::csky_target_feature)),
-    ("3e3r2", Unstable(sym::csky_target_feature)),
-    ("3e3r3", Unstable(sym::csky_target_feature)),
-    ("3e7", Unstable(sym::csky_target_feature)),
-    ("7e10", Unstable(sym::csky_target_feature)),
-    ("cache", Unstable(sym::csky_target_feature)),
-    ("doloop", Unstable(sym::csky_target_feature)),
-    ("dsp1e2", Unstable(sym::csky_target_feature)),
-    ("dspe60", Unstable(sym::csky_target_feature)),
-    ("e1", Unstable(sym::csky_target_feature)),
-    ("e2", Unstable(sym::csky_target_feature)),
-    ("edsp", Unstable(sym::csky_target_feature)),
-    ("elrw", Unstable(sym::csky_target_feature)),
-    ("float1e2", Unstable(sym::csky_target_feature)),
-    ("float1e3", Unstable(sym::csky_target_feature)),
-    ("float3e4", Unstable(sym::csky_target_feature)),
-    ("float7e60", Unstable(sym::csky_target_feature)),
-    ("floate1", Unstable(sym::csky_target_feature)),
-    ("hard-tp", Unstable(sym::csky_target_feature)),
-    ("high-registers", Unstable(sym::csky_target_feature)),
-    ("hwdiv", Unstable(sym::csky_target_feature)),
-    ("mp", Unstable(sym::csky_target_feature)),
-    ("mp1e2", Unstable(sym::csky_target_feature)),
-    ("nvic", Unstable(sym::csky_target_feature)),
-    ("trust", Unstable(sym::csky_target_feature)),
-    ("vdsp2e60f", Unstable(sym::csky_target_feature)),
-    ("vdspv1", Unstable(sym::csky_target_feature)),
-    ("vdspv2", Unstable(sym::csky_target_feature)),
+    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
+    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
+    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
+    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
+    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
+    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
+    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
+    ("cache", Unstable(sym::csky_target_feature), &[]),
+    ("doloop", Unstable(sym::csky_target_feature), &[]),
+    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
+    ("dspe60", Unstable(sym::csky_target_feature), &[]),
+    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
+    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
+    ("edsp", Unstable(sym::csky_target_feature), &[]),
+    ("elrw", Unstable(sym::csky_target_feature), &[]),
+    ("float1e2", Unstable(sym::csky_target_feature), &[]),
+    ("float1e3", Unstable(sym::csky_target_feature), &[]),
+    ("float3e4", Unstable(sym::csky_target_feature), &[]),
+    ("float7e60", Unstable(sym::csky_target_feature), &[]),
+    ("floate1", Unstable(sym::csky_target_feature), &[]),
+    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
+    ("high-registers", Unstable(sym::csky_target_feature), &[]),
+    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
+    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
+    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
+    ("nvic", Unstable(sym::csky_target_feature), &[]),
+    ("trust", Unstable(sym::csky_target_feature), &[]),
+    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
+    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
+    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
     // tidy-alphabetical-end
     //fpu
     // tidy-alphabetical-start
-    ("fdivdu", Unstable(sym::csky_target_feature)),
-    ("fpuv2_df", Unstable(sym::csky_target_feature)),
-    ("fpuv2_sf", Unstable(sym::csky_target_feature)),
-    ("fpuv3_df", Unstable(sym::csky_target_feature)),
-    ("fpuv3_hf", Unstable(sym::csky_target_feature)),
-    ("fpuv3_hi", Unstable(sym::csky_target_feature)),
-    ("fpuv3_sf", Unstable(sym::csky_target_feature)),
-    ("hard-float", Unstable(sym::csky_target_feature)),
-    ("hard-float-abi", Unstable(sym::csky_target_feature)),
+    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
+    ("hard-float", Unstable(sym::csky_target_feature), &[]),
+    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("d", Unstable(sym::loongarch_target_feature)),
-    ("f", Unstable(sym::loongarch_target_feature)),
-    ("frecipe", Unstable(sym::loongarch_target_feature)),
-    ("lasx", Unstable(sym::loongarch_target_feature)),
-    ("lbt", Unstable(sym::loongarch_target_feature)),
-    ("lsx", Unstable(sym::loongarch_target_feature)),
-    ("lvz", Unstable(sym::loongarch_target_feature)),
-    ("relax", Unstable(sym::loongarch_target_feature)),
-    ("ual", Unstable(sym::loongarch_target_feature)),
+    ("d", Unstable(sym::loongarch_target_feature), &["f"]),
+    ("f", Unstable(sym::loongarch_target_feature), &[]),
+    ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
+    ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
+    ("lbt", Unstable(sym::loongarch_target_feature), &[]),
+    ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
+    ("lvz", Unstable(sym::loongarch_target_feature), &[]),
+    ("relax", Unstable(sym::loongarch_target_feature), &[]),
+    ("ual", Unstable(sym::loongarch_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("backchain", Unstable(sym::s390x_target_feature)),
-    ("vector", Unstable(sym::s390x_target_feature)),
+    ("backchain", Unstable(sym::s390x_target_feature), &[]),
+    ("vector", Unstable(sym::s390x_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
@@ -426,10 +448,13 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
         .chain(LOONGARCH_ALLOWED_FEATURES)
         .chain(IBMZ_ALLOWED_FEATURES)
         .cloned()
+        .map(|(f, s, _)| (f, s))
 }
 
 impl super::spec::Target {
-    pub fn supported_target_features(&self) -> &'static [(&'static str, Stability)] {
+    pub fn supported_target_features(
+        &self,
+    ) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
         match &*self.arch {
             "arm" => ARM_ALLOWED_FEATURES,
             "aarch64" | "arm64ec" => AARCH64_ALLOWED_FEATURES,
@@ -453,4 +478,28 @@ impl super::spec::Target {
             _ => &[],
         }
     }
+
+    pub fn implied_target_features(
+        &self,
+        base_features: impl Iterator<Item = Symbol>,
+    ) -> FxHashSet<Symbol> {
+        let implied_features = self
+            .supported_target_features()
+            .iter()
+            .map(|(f, _, i)| (Symbol::intern(f), i))
+            .collect::<FxHashMap<_, _>>();
+
+        // implied target features have their own implied target features, so we traverse the
+        // map until there are no more features to add
+        let mut features = FxHashSet::default();
+        let mut new_features = base_features.collect::<Vec<Symbol>>();
+        while let Some(new_feature) = new_features.pop() {
+            if features.insert(new_feature) {
+                if let Some(implied_features) = implied_features.get(&new_feature) {
+                    new_features.extend(implied_features.iter().copied().map(Symbol::intern))
+                }
+            }
+        }
+        features
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index daabdec8f9e..8ccb2a8483a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -60,12 +60,11 @@ use rustc_hir::{self as hir};
 use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::error::TypeErrorToStringExt;
+use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
 use rustc_middle::ty::{
-    self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt,
+    self, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt,
 };
 use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 56ea70bcf1d..f6dd7898fb2 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -1,13 +1,11 @@
-use crate::error_reporting::TypeErrCtxt;
-use crate::errors::{
-    AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError,
-    SourceKindMultiSuggestion, SourceKindSubdiag,
-};
-use crate::infer::InferCtxt;
-use rustc_errors::{codes::*, Diag, IntoDiagArg};
+use std::borrow::Cow;
+use std::iter;
+use std::path::PathBuf;
+
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, IntoDiagArg};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
-use rustc_hir::def::{CtorOf, DefKind, Namespace};
+use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
@@ -21,9 +19,13 @@ use rustc_middle::ty::{
 };
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{BytePos, Span, DUMMY_SP};
-use std::borrow::Cow;
-use std::iter;
-use std::path::PathBuf;
+
+use crate::error_reporting::TypeErrCtxt;
+use crate::errors::{
+    AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError,
+    SourceKindMultiSuggestion, SourceKindSubdiag,
+};
+use crate::infer::InferCtxt;
 
 pub enum TypeAnnotationNeeded {
     /// ```compile_fail,E0282
@@ -932,13 +934,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
             // which makes this somewhat difficult and prevents us from just
             // using `self.path_inferred_arg_iter` here.
             hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
-            // FIXME(TaKO8Ki): Ideally we should support this. For that
-            // we have to map back from the self type to the
-            // type alias though. That's difficult.
+            // FIXME(TaKO8Ki): Ideally we should support other kinds,
+            // such as `TyAlias` or `AssocTy`. For that we have to map
+            // back from the self type to the type alias though. That's difficult.
             //
             // See the `need_type_info/issue-103053.rs` test for
             // a example.
-            if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+            if matches!(path.res, Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) => {
                 if let Some(ty) = self.opt_node_type(expr.hir_id)
                     && let ty::Adt(_, args) = ty.kind()
                 {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs
index 74dcde03639..8f84d771216 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs
@@ -1,21 +1,17 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where both the regions are anonymous.
 
-use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type;
-use crate::error_reporting::infer::nice_region_error::util::AnonymousParamInfo;
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::AddLifetimeParamsSuggestion;
-use crate::errors::LifetimeMismatch;
-use crate::errors::LifetimeMismatchLabels;
-use crate::infer::RegionResolutionError;
-use crate::infer::SubregionOrigin;
-
-use rustc_errors::Subdiagnostic;
-use rustc_errors::{Diag, ErrorGuaranteed};
+use rustc_errors::{Diag, ErrorGuaranteed, Subdiagnostic};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::Ty;
 use rustc_middle::ty::{Region, TyCtxt};
 
+use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type;
+use crate::error_reporting::infer::nice_region_error::util::AnonymousParamInfo;
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::{AddLifetimeParamsSuggestion, LifetimeMismatch, LifetimeMismatchLabels};
+use crate::infer::{RegionResolutionError, SubregionOrigin};
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
     ///
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
index a892ce58861..3f35391be13 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
@@ -1,4 +1,5 @@
 use core::ops::ControlFlow;
+
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
index 550cc455e01..221f6675d22 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
@@ -1,14 +1,6 @@
 //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
 //! to hold.
 
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
-use crate::errors::{
-    DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
-};
-use crate::infer::RegionResolutionError;
-use crate::infer::{SubregionOrigin, TypeTrace};
-use crate::traits::ObligationCauseCode;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
@@ -16,6 +8,14 @@ use rustc_hir::intravisit::Visitor;
 use rustc_middle::bug;
 use rustc_middle::ty::TypeVisitor;
 
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::{
+    note_and_explain, DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag,
+    IntroducesStaticBecauseUnmetLifetimeReq, MismatchedStaticLifetime,
+};
+use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace};
+use crate::traits::ObligationCauseCode;
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaranteed> {
         let error = self.error.as_ref()?;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
index b83ecd8320c..79a770ac9b3 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
@@ -1,11 +1,12 @@
-use crate::error_reporting::TypeErrCtxt;
-use crate::infer::RegionResolutionError;
-use crate::infer::RegionResolutionError::*;
 use rustc_errors::{Diag, ErrorGuaranteed};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Span;
 
+use crate::error_reporting::TypeErrCtxt;
+use crate::infer::RegionResolutionError;
+use crate::infer::RegionResolutionError::*;
+
 mod different_lifetimes;
 pub mod find_anon_type;
 mod mismatched_static_lifetime;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
index d1802d2f5ee..f91a81f76f4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
@@ -1,13 +1,14 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where one region is named and the other is anonymous.
 
-use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type;
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::ExplicitLifetimeRequired;
 use rustc_errors::Diag;
 use rustc_middle::ty;
 use rustc_span::symbol::kw;
 
+use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type;
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::ExplicitLifetimeRequired;
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
     /// an anonymous region, emit an descriptive diagnostic error.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index 476ac3f1720..8da0edbeb02 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
@@ -1,12 +1,5 @@
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::{
-    ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
-    TraitPlaceholderMismatch, TyOrSig,
-};
-use crate::infer::RegionResolutionError;
-use crate::infer::ValuePairs;
-use crate::infer::{SubregionOrigin, TypeTrace};
-use crate::traits::{ObligationCause, ObligationCauseCode};
+use std::fmt;
+
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Diag, IntoDiagArg};
 use rustc_hir::def::Namespace;
@@ -14,10 +7,15 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_middle::bug;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, RePlaceholder, Region, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, RePlaceholder, Region, TyCtxt};
 
-use std::fmt;
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::{
+    ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
+    TraitPlaceholderMismatch, TyOrSig,
+};
+use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace, ValuePairs};
+use crate::traits::{ObligationCause, ObligationCauseCode};
 
 // HACK(eddyb) maybe move this in a more central location.
 #[derive(Copy, Clone)]
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
index e9f17a3e3e2..9c772f42cca 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
@@ -1,10 +1,11 @@
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::PlaceholderRelationLfNotSatisfied;
-use crate::infer::{RegionResolutionError, SubregionOrigin};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::Diag;
 use rustc_middle::ty::{self, RePlaceholder, Region};
 
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::PlaceholderRelationLfNotSatisfied;
+use crate::infer::{RegionResolutionError, SubregionOrigin};
+
 impl<'tcx> NiceRegionError<'_, 'tcx> {
     /// Emitted wwhen given a `ConcreteFailure` when relating two placeholders.
     pub(super) fn try_report_placeholder_relation(&self) -> Option<Diag<'tcx>> {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index e5d97976534..dc775b824da 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -1,13 +1,5 @@
 //! Error Reporting for static impl Traits.
 
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::{
-    ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
-    ReqIntroducedLocations,
-};
-use crate::infer::RegionResolutionError;
-use crate::infer::{SubregionOrigin, TypeTrace};
-use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic};
 use rustc_hir::def_id::DefId;
@@ -19,10 +11,17 @@ use rustc_hir::{
 use rustc_middle::ty::{
     self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-use rustc_span::def_id::LocalDefId;
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::{
+    ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+    ReqIntroducedLocations,
+};
+use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace};
+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
index c58c7e13551..09af00beba7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
@@ -1,9 +1,5 @@
 //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
 
-use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
-use crate::infer::RegionResolutionError;
-use crate::infer::{Subtype, ValuePairs};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -16,6 +12,10 @@ use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
 use rustc_span::Span;
 
+use crate::error_reporting::infer::nice_region_error::NiceRegionError;
+use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
+use crate::infer::{RegionResolutionError, Subtype, ValuePairs};
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuaranteed> {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
index aeb3049c2ae..04e1be22a4d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
@@ -1,10 +1,3 @@
-use crate::error_reporting::infer::{note_and_explain_region, TypeErrCtxt};
-use crate::errors::{
-    note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
-    RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
-};
-use crate::fluent_generated as fluent;
-use crate::infer::{self, SubregionOrigin};
 use rustc_errors::{Diag, Subdiagnostic};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::traits::ObligationCauseCode;
@@ -13,6 +6,13 @@ use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
 use rustc_span::symbol::kw;
 
 use super::ObligationCauseAsDiagArg;
+use crate::error_reporting::infer::{note_and_explain_region, TypeErrCtxt};
+use crate::errors::{
+    note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
+    RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
+};
+use crate::fluent_generated as fluent;
+use crate::infer::{self, SubregionOrigin};
 
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index f9110cfb3b9..864510bb650 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -2,14 +2,12 @@ use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diag, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::print::Printer;
-use rustc_middle::{
-    traits::ObligationCause,
-    ty::{self, error::TypeError, print::FmtPrinter, suggest_constraining_type_param, Ty},
-};
-use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::print::{FmtPrinter, Printer};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
+use rustc_span::def_id::DefId;
+use rustc_span::{sym, BytePos, Span, Symbol};
 
 use crate::error_reporting::TypeErrCtxt;
 use crate::infer::InferCtxtExt;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 1ef32d110b3..ee159aa0b77 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -1,5 +1,5 @@
-use crate::error_reporting::infer::hir::Path;
 use core::ops::ControlFlow;
+
 use hir::def::CtorKind;
 use hir::intravisit::{walk_expr, walk_stmt, Visitor};
 use hir::{LetStmt, QPath};
@@ -7,8 +7,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::MatchSource;
-use rustc_hir::Node;
+use rustc_hir::{MatchSource, Node};
 use rustc_middle::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
     StatementAsExpression,
@@ -17,6 +16,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
 use rustc_span::{sym, Span};
 
+use crate::error_reporting::infer::hir::Path;
 use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{
     ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 72a4d4c1205..9ab47057859 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -388,39 +388,67 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 trait_impls.non_blanket_impls().values().flatten().count();
                             // If there is only one implementation of the trait, suggest using it.
                             // Otherwise, use a placeholder comment for the implementation.
-                            let (message, self_type) = if non_blanket_impl_count == 1 {
+                            let (message, self_types) = if non_blanket_impl_count == 1 {
                                 (
                                     "use the fully-qualified path to the only available \
                                      implementation",
-                                    format!(
+                                    vec![format!(
                                         "{}",
                                         self.tcx.type_of(impl_def_id).instantiate_identity()
-                                    ),
+                                    )],
+                                )
+                            } else if non_blanket_impl_count < 20 {
+                                (
+                                    "use a fully-qualified path to one of the available \
+                                     implementations",
+                                    trait_impls
+                                        .non_blanket_impls()
+                                        .values()
+                                        .flatten()
+                                        .map(|id| {
+                                            format!(
+                                                "{}",
+                                                self.tcx.type_of(id).instantiate_identity()
+                                            )
+                                        })
+                                        .collect::<Vec<String>>(),
                                 )
                             } else {
                                 (
                                     "use a fully-qualified path to a specific available \
                                      implementation",
-                                    "/* self type */".to_string(),
+                                    vec!["/* self type */".to_string()],
                                 )
                             };
-                            let mut suggestions =
-                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
-                            if let Some(generic_arg) = trait_path_segment.args {
-                                let between_span =
-                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
-                                // get rid of :: between Trait and <type>
-                                // must be '::' between them, otherwise the parser won't accept the code
-                                suggestions.push((between_span, "".to_string()));
-                                suggestions
-                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
-                            } else {
-                                suggestions.push((
-                                    trait_path_segment.ident.span.shrink_to_hi(),
-                                    ">".to_string(),
-                                ));
-                            }
-                            err.multipart_suggestion(
+                            let suggestions: Vec<_> = self_types
+                                .into_iter()
+                                .map(|self_type| {
+                                    let mut suggestions = vec![(
+                                        path.span.shrink_to_lo(),
+                                        format!("<{self_type} as "),
+                                    )];
+                                    if let Some(generic_arg) = trait_path_segment.args {
+                                        let between_span = trait_path_segment
+                                            .ident
+                                            .span
+                                            .between(generic_arg.span_ext);
+                                        // get rid of :: between Trait and <type>
+                                        // must be '::' between them, otherwise the parser won't accept the code
+                                        suggestions.push((between_span, "".to_string()));
+                                        suggestions.push((
+                                            generic_arg.span_ext.shrink_to_hi(),
+                                            ">".to_string(),
+                                        ));
+                                    } else {
+                                        suggestions.push((
+                                            trait_path_segment.ident.span.shrink_to_hi(),
+                                            ">".to_string(),
+                                        ));
+                                    }
+                                    suggestions
+                                })
+                                .collect();
+                            err.multipart_suggestions(
                                 message,
                                 suggestions,
                                 Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index a7ea308a818..f908d8a6870 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
@@ -1,31 +1,17 @@
-use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
-use super::suggestions::get_explanation_based_on_obligation;
-use crate::error_reporting::infer::TyCategory;
-use crate::error_reporting::traits::report_object_safety_error;
-use crate::error_reporting::TypeErrCtxt;
-use crate::errors::{
-    AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
-};
-use crate::infer::InferCtxtExt as _;
-use crate::infer::{self, InferCtxt};
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::NormalizeExt;
-use crate::traits::{
-    elaborate, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
-    ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch,
-    TraitNotObjectSafe,
-};
 use core::ops::ControlFlow;
+use std::borrow::Cow;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::{pluralize, struct_span_code_err, Applicability, StringPart};
-use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
+use rustc_errors::{
+    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey,
+    StringPart,
+};
 use rustc_hir::def::Namespace;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::Node;
-use rustc_hir::{self as hir, LangItem};
+use rustc_hir::{self as hir, LangItem, Node};
 use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::traits::SignatureMismatchData;
@@ -42,11 +28,25 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, Span, Symbol, DUMMY_SP};
-use std::borrow::Cow;
 
+use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
+use super::suggestions::get_explanation_based_on_obligation;
 use super::{
     ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst,
 };
+use crate::error_reporting::infer::TyCategory;
+use crate::error_reporting::traits::report_object_safety_error;
+use crate::error_reporting::TypeErrCtxt;
+use crate::errors::{
+    AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
+};
+use crate::infer::{self, InferCtxt, InferCtxtExt as _};
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::{
+    elaborate, MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause,
+    ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation, SelectionError,
+    SignatureMismatch, TraitNotObjectSafe,
+};
 
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// The `root_obligation` parameter should be the `root_obligation` field
@@ -687,10 +687,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let mut applied_do_not_recommend = false;
         loop {
             if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
-                if self.tcx.has_attrs_with_path(
-                    c.impl_or_alias_def_id,
-                    &[sym::diagnostic, sym::do_not_recommend],
-                ) {
+                if self.tcx.do_not_recommend_impl(c.impl_or_alias_def_id) {
                     let code = (*c.derived.parent_code).clone();
                     obligation.cause.map_code(|_| code);
                     obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
@@ -944,8 +941,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // The current method call returns `Result<_, ()>`
                 && self.can_eq(obligation.param_env, ty, found_ty)
                 // There's a single argument in the method call and it is a closure
-                && args.len() == 1
-                && let Some(arg) = args.get(0)
+                && let [arg] = args
                 && let hir::ExprKind::Closure(closure) = arg.kind
                 // The closure has a block for its body with no tail expression
                 && let body = self.tcx.hir().body(closure.body)
@@ -1625,9 +1621,127 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         other: bool,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
-        // If we have a single implementation, try to unify it with the trait ref
-        // that failed. This should uncover a better hint for what *is* implemented.
+        let alternative_candidates = |def_id: DefId| {
+            let mut impl_candidates: Vec<_> = self
+                .tcx
+                .all_impls(def_id)
+                // ignore `do_not_recommend` items
+                .filter(|def_id| !self.tcx.do_not_recommend_impl(*def_id))
+                // Ignore automatically derived impls and `!Trait` impls.
+                .filter_map(|def_id| self.tcx.impl_trait_header(def_id))
+                .filter_map(|header| {
+                    (header.polarity != ty::ImplPolarity::Negative
+                        || self.tcx.is_automatically_derived(def_id))
+                    .then(|| header.trait_ref.instantiate_identity())
+                })
+                .filter(|trait_ref| {
+                    let self_ty = trait_ref.self_ty();
+                    // Avoid mentioning type parameters.
+                    if let ty::Param(_) = self_ty.kind() {
+                        false
+                    }
+                    // Avoid mentioning types that are private to another crate
+                    else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
+                        // FIXME(compiler-errors): This could be generalized, both to
+                        // be more granular, and probably look past other `#[fundamental]`
+                        // types, too.
+                        self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
+                    } else {
+                        true
+                    }
+                })
+                .collect();
+
+            impl_candidates.sort_by_key(|tr| tr.to_string());
+            impl_candidates.dedup();
+            impl_candidates
+        };
+
+        // We'll check for the case where the reason for the mismatch is that the trait comes from
+        // one crate version and the type comes from another crate version, even though they both
+        // are from the same crate.
+        let trait_def_id = trait_ref.def_id();
+        if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind()
+            && let found_type = def.did()
+            && trait_def_id.krate != found_type.krate
+            && self.tcx.crate_name(trait_def_id.krate) == self.tcx.crate_name(found_type.krate)
+        {
+            let name = self.tcx.crate_name(trait_def_id.krate);
+            let spans: Vec<_> = [trait_def_id, found_type]
+                .into_iter()
+                .filter_map(|def_id| self.tcx.extern_crate(def_id))
+                .map(|data| {
+                    let dependency = if data.dependency_of == LOCAL_CRATE {
+                        "direct dependency of the current crate".to_string()
+                    } else {
+                        let dep = self.tcx.crate_name(data.dependency_of);
+                        format!("dependency of crate `{dep}`")
+                    };
+                    (
+                        data.span,
+                        format!("one version of crate `{name}` is used here, as a {dependency}"),
+                    )
+                })
+                .collect();
+            let mut span: MultiSpan = spans.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
+            for (sp, label) in spans.into_iter() {
+                span.push_span_label(sp, label);
+            }
+            err.highlighted_span_help(
+                span,
+                vec![
+                    StringPart::normal("you have ".to_string()),
+                    StringPart::highlighted("multiple different versions".to_string()),
+                    StringPart::normal(" of crate `".to_string()),
+                    StringPart::highlighted(format!("{name}")),
+                    StringPart::normal("` in your dependency graph".to_string()),
+                ],
+            );
+            let candidates = if impl_candidates.is_empty() {
+                alternative_candidates(trait_def_id)
+            } else {
+                impl_candidates.into_iter().map(|cand| cand.trait_ref).collect()
+            };
+            if let Some((sp_candidate, sp_found)) = candidates.iter().find_map(|trait_ref| {
+                if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind()
+                    && let candidate_def_id = def.did()
+                    && let Some(name) = self.tcx.opt_item_name(candidate_def_id)
+                    && let Some(found) = self.tcx.opt_item_name(found_type)
+                    && name == found
+                    && candidate_def_id.krate != found_type.krate
+                    && self.tcx.crate_name(candidate_def_id.krate)
+                        == self.tcx.crate_name(found_type.krate)
+                {
+                    // A candidate was found of an item with the same name, from two separate
+                    // versions of the same crate, let's clarify.
+                    Some((self.tcx.def_span(candidate_def_id), self.tcx.def_span(found_type)))
+                } else {
+                    None
+                }
+            }) {
+                let mut span: MultiSpan = vec![sp_candidate, sp_found].into();
+                span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
+                span.push_span_label(sp_candidate, "this type implements the required trait");
+                span.push_span_label(sp_found, "this type doesn't implement the required trait");
+                err.highlighted_span_note(
+                    span,
+                    vec![
+                        StringPart::normal(
+                            "two types coming from two different versions of the same crate are \
+                             different types "
+                                .to_string(),
+                        ),
+                        StringPart::highlighted("even if they look the same".to_string()),
+                    ],
+                );
+            }
+            err.help("you can use `cargo tree` to explore your dependency tree");
+            return true;
+        }
+
         if let [single] = &impl_candidates {
+            // If we have a single implementation, try to unify it with the trait ref
+            // that failed. This should uncover a better hint for what *is* implemented.
             if self.probe(|_| {
                 let ocx = ObligationCtxt::new(self);
 
@@ -1782,12 +1896,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         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],
-                )
-            })
+            .filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id))
             .collect::<Vec<_>>();
 
         let def_id = trait_ref.def_id();
@@ -1799,43 +1908,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
                 return false;
             }
-            let mut impl_candidates: Vec<_> = self
-                .tcx
-                .all_impls(def_id)
-                // ignore `do_not_recommend` items
-                .filter(|def_id| {
-                    !self
-                        .tcx
-                        .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend])
-                })
-                // Ignore automatically derived impls and `!Trait` impls.
-                .filter_map(|def_id| self.tcx.impl_trait_header(def_id))
-                .filter_map(|header| {
-                    (header.polarity != ty::ImplPolarity::Negative
-                        || self.tcx.is_automatically_derived(def_id))
-                    .then(|| header.trait_ref.instantiate_identity())
-                })
-                .filter(|trait_ref| {
-                    let self_ty = trait_ref.self_ty();
-                    // Avoid mentioning type parameters.
-                    if let ty::Param(_) = self_ty.kind() {
-                        false
-                    }
-                    // Avoid mentioning types that are private to another crate
-                    else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
-                        // FIXME(compiler-errors): This could be generalized, both to
-                        // be more granular, and probably look past other `#[fundamental]`
-                        // types, too.
-                        self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
-                    } else {
-                        true
-                    }
-                })
-                .collect();
-
-            impl_candidates.sort_by_key(|tr| tr.to_string());
-            impl_candidates.dedup();
-            return report(impl_candidates, err);
+            return report(alternative_candidates(def_id), err);
         }
 
         // Sort impl candidates so that ordering is consistent for UI tests.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 89ae6f4ccab..40a1c184009 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -19,11 +19,10 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{ErrorGuaranteed, ExpnKind, Span};
 
+pub use self::overflow::*;
 use crate::error_reporting::TypeErrCtxt;
 use crate::traits::{FulfillmentError, FulfillmentErrorCode};
 
-pub use self::overflow::*;
-
 // When outputting impl candidates, prefer showing those that are more similar.
 //
 // We also compare candidates after skipping lifetimes, which has a lower
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index f65de590ccf..f656f9b0e38 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -1,29 +1,27 @@
-use super::{ObligationCauseCode, PredicateObligation};
-use crate::error_reporting::TypeErrCtxt;
-use crate::errors::{
-    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
-};
-use crate::infer::InferCtxtExt;
-use rustc_ast::AttrArgs;
-use rustc_ast::AttrArgsEq;
-use rustc_ast::AttrKind;
-use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
-use rustc_attr as attr;
+use std::iter;
+use std::path::PathBuf;
+
+use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
-use rustc_hir as hir;
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{ParseMode, Parser, Piece, Position};
 use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-use std::iter;
-use std::path::PathBuf;
+use {rustc_attr as attr, rustc_hir as hir};
+
+use super::{ObligationCauseCode, PredicateObligation};
+use crate::error_reporting::TypeErrCtxt;
+use crate::errors::{
+    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
+use crate::infer::InferCtxtExt;
 
 /// The symbols which are always allowed in a format string
 static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
@@ -75,10 +73,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             });
 
-            let impl_def_id_and_args = if self_match_impls.len() == 1 {
-                self_match_impls[0]
-            } else if fuzzy_match_impls.len() == 1 {
-                fuzzy_match_impls[0]
+            let impl_def_id_and_args = if let [impl_] = self_match_impls[..] {
+                impl_
+            } else if let [impl_] = fuzzy_match_impls[..] {
+                impl_
             } else {
                 return None;
             };
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 d1381d24764..9269177eb50 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1,34 +1,33 @@
 // ignore-tidy-filelength
 
-use super::{
-    DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode,
-    PredicateObligation,
-};
-
-use crate::error_reporting::TypeErrCtxt;
-use crate::errors;
-use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt};
+use std::assert_matches::debug_assert_matches;
+use std::borrow::Cow;
+use std::iter;
 
+use itertools::{EitherOrBoth, Itertools};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, EmissionGuarantee, MultiSpan,
-    Style, SuggestionStyle,
+    pluralize, struct_span_code_err, Applicability, Diag, EmissionGuarantee, MultiSpan, Style,
+    SuggestionStyle,
 };
 use rustc_hir as hir;
-use rustc_hir::def::CtorOf;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::is_range_literal;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
-use rustc_infer::infer::InferCtxt;
-use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
+use rustc_hir::{
+    is_range_literal, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
+};
+use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_middle::hir::map;
 use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::print::PrintPolyTraitRefExt;
+use rustc_middle::ty::print::{
+    with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _,
+    PrintPolyTraitRefExt, PrintTraitPredicateExt as _,
+};
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
     InferTy, IsSuggestable, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder,
@@ -39,19 +38,16 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
-use std::assert_matches::debug_assert_matches;
-use std::borrow::Cow;
-use std::iter;
 
+use super::{
+    DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode,
+    PredicateObligation,
+};
+use crate::error_reporting::TypeErrCtxt;
+use crate::errors;
 use crate::infer::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_middle::ty::print::{
-    with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _,
-    PrintTraitPredicateExt as _,
-};
-
-use itertools::EitherOrBoth;
-use itertools::Itertools;
+use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt};
 
 #[derive(Debug)]
 pub enum CoroutineInteriorOrUpvar {
@@ -5304,7 +5300,8 @@ impl<'v> Visitor<'v> for FindTypeParam {
         match ty.kind {
             hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
             hir::TyKind::Path(hir::QPath::Resolved(None, path))
-                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+                if let [segment] = path.segments
+                    && segment.ident.name == self.param =>
             {
                 if !self.nested {
                     debug!(?ty, "FindTypeParam::visit_ty");
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 0ee4485a365..78f1f7d9b9b 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,19 +1,18 @@
+use std::path::PathBuf;
+
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::codes::*;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
+    Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
     EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::FnRetTy;
-use rustc_hir::GenericParamKind;
+use rustc_hir::{FnRetTy, GenericParamKind};
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
-use rustc_middle::ty::{
-    self, print::PrintTraitRefExt as _, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty,
-    TyCtxt,
-};
+use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
+use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{BytePos, Span};
 
@@ -22,8 +21,6 @@ use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlig
 use crate::error_reporting::infer::ObligationCauseAsDiagArg;
 use crate::fluent_generated as fluent;
 
-use std::path::PathBuf;
-
 pub mod note_and_explain;
 
 #[derive(Diagnostic)]
@@ -1585,10 +1582,7 @@ pub enum TypeErrorAdditionalDiags {
         span: Span,
         code: String,
     },
-    #[multipart_suggestion(
-        trait_selection_meant_str_literal,
-        applicability = "machine-applicable"
-    )]
+    #[multipart_suggestion(trait_selection_meant_str_literal, applicability = "machine-applicable")]
     MeantStrLiteral {
         #[suggestion_part(code = "\"")]
         start: Span,
diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
index 1f18cd8c8d8..b1477763028 100644
--- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -1,10 +1,12 @@
-use crate::error_reporting::infer::nice_region_error::find_anon_type;
-use crate::fluent_generated as fluent;
 use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::{symbol::kw, Span};
+use rustc_span::symbol::kw;
+use rustc_span::Span;
+
+use crate::error_reporting::infer::nice_region_error::find_anon_type;
+use crate::fluent_generated as fluent;
 
 struct DescriptionCtx<'a> {
     span: Option<Span>,
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index ad087620ae0..c22925b73e3 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,20 +1,18 @@
-use crate::infer::at::ToTrace;
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext};
+use std::fmt::Debug;
 
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+pub use rustc_infer::infer::*;
 use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, Upcast};
+use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
 use rustc_span::DUMMY_SP;
 
-use std::fmt::Debug;
-
-pub use rustc_infer::infer::*;
+use crate::infer::at::ToTrace;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext};
 
 #[extension(pub trait InferCtxtExt<'tcx>)]
 impl<'tcx> InferCtxt<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 5f986e22f51..65762cfcd2e 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -1,10 +1,11 @@
-use crate::traits::ScrubbedTraitError;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, RegionResolutionError};
 use rustc_macros::extension;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 
+use crate::traits::ScrubbedTraitError;
+
 #[extension(pub trait InferCtxtRegionExt<'tcx>)]
 impl<'tcx> InferCtxt<'tcx> {
     /// Resolve regions, using the deep normalizer to normalize any type-outlives
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 76b88aeb0f7..de8951ef720 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -13,13 +13,11 @@ use rustc_middle::bug;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
-use rustc_span::symbol::sym;
-
-use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError};
 
 use super::delegate::SolverDelegate;
 use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use super::Certainty;
+use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError};
 
 /// A trait engine using the new trait solver.
 ///
@@ -441,10 +439,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             source: CandidateSource::Impl(impl_def_id),
             result: _,
         } = candidate.kind()
-            && goal
-                .infcx()
-                .tcx
-                .has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
+            && goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
         {
             return ControlFlow::Break(self.obligation.clone());
         }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index e8de8457440..1a459aa484f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -9,6 +9,8 @@
 //! coherence right now and was annoying to implement, so I am leaving it
 //! as is until we start using it for something else.
 
+use std::assert_matches::assert_matches;
+
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
@@ -273,10 +275,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
                     steps.push(step)
                 }
                 inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
-                    assert!(matches!(
+                    assert_matches!(
                         shallow_certainty.replace(c),
                         None | Some(Certainty::Maybe(MaybeCause::Ambiguity))
-                    ));
+                    );
                 }
                 inspect::ProbeStep::NestedProbe(ref probe) => {
                     match probe.kind {
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index ddaef7c159f..c93c40b4826 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -1,20 +1,22 @@
+use std::assert_matches::assert_matches;
 use std::fmt::Debug;
 use std::marker::PhantomData;
 
-use crate::error_reporting::traits::OverflowCause;
-use crate::error_reporting::InferCtxtErrorExt;
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine};
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
-use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, UniverseIndex,
+};
 
 use super::{FulfillmentCtxt, NextSolverError};
+use crate::error_reporting::traits::OverflowCause;
+use crate::error_reporting::InferCtxtErrorExt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
 
 /// Deeply normalize all aliases in `value`. This does not handle inference and expects
 /// its input to be already fully resolved.
@@ -62,7 +64,7 @@ where
     E: FromSolverError<'tcx, NextSolverError<'tcx>>,
 {
     fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result<Ty<'tcx>, Vec<E>> {
-        assert!(matches!(alias_ty.kind(), ty::Alias(..)));
+        assert_matches!(alias_ty.kind(), ty::Alias(..));
 
         let infcx = self.at.infcx;
         let tcx = infcx.tcx;
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 796f7fd5a54..29f78f9d5f0 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -1,11 +1,8 @@
 //! Support code for rustdoc and external tools.
 //! You really don't want to be using this unless you need to.
 
-use super::*;
-
-use crate::errors::UnableToConstructConstantValue;
-use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::traits::project::ProjectAndUnifyResult;
+use std::collections::VecDeque;
+use std::iter;
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_data_structures::unord::UnordSet;
@@ -13,8 +10,10 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 
-use std::collections::VecDeque;
-use std::iter;
+use super::*;
+use crate::errors::UnableToConstructConstantValue;
+use crate::infer::region_constraints::{Constraint, RegionConstraintData};
+use crate::traits::project::ProjectAndUnifyResult;
 
 // FIXME(twk): this is obviously not nice to duplicate like that
 #[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 7e996c5c5ef..2d843d8f174 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -4,15 +4,8 @@
 //! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
 //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
-use crate::infer::outlives::env::OutlivesEnvironment;
-use crate::infer::InferOk;
-use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
-use crate::solve::{deeply_normalize_for_diagnostics, inspect};
-use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::NormalizeExt;
-use crate::traits::SkipLeakCheck;
-use crate::traits::{util, FulfillmentErrorCode};
-use crate::traits::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
+use std::fmt::Debug;
+
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def::DefKind;
@@ -28,10 +21,18 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 pub use rustc_next_trait_solver::coherence::*;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
-use std::fmt::Debug;
 
 use super::ObligationCtxt;
 use crate::error_reporting::traits::suggest_new_overflow_limit;
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::InferOk;
+use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::solve::{deeply_normalize_for_diagnostics, inspect};
+use crate::traits::select::IntercrateAmbiguityCause;
+use crate::traits::{
+    util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
+    SelectionContext, SkipLeakCheck,
+};
 
 pub struct OverlapResult<'tcx> {
     pub impl_header: ty::ImplHeader<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 49730b532a3..de1d4ef15ac 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -1,16 +1,6 @@
 use std::cell::RefCell;
 use std::fmt::Debug;
 
-use super::{FromSolverError, TraitEngine};
-use super::{FulfillmentContext, ScrubbedTraitError};
-use crate::error_reporting::InferCtxtErrorExt;
-use crate::regions::InferCtxtRegionExt;
-use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
-use crate::solve::NextSolverError;
-use crate::traits::fulfill::OldSolverError;
-use crate::traits::NormalizeExt;
-use crate::traits::StructurallyNormalizeExt;
-use crate::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -19,16 +9,22 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::RegionResolutionError;
-use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError};
 use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::Upcast;
-use rustc_middle::ty::Variance;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
+
+use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
+use crate::error_reporting::InferCtxtErrorExt;
+use crate::regions::InferCtxtRegionExt;
+use crate::solve::{FulfillmentCtxt as NextFulfillmentCtxt, NextSolverError};
+use crate::traits::fulfill::OldSolverError;
+use crate::traits::{
+    FulfillmentError, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
+    StructurallyNormalizeExt,
+};
 
 #[extension(pub trait TraitEngineExt<'tcx, E>)]
 impl<'tcx, E> dyn TraitEngine<'tcx, E>
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index cc0bb7a60b2..a6db22ec15a 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,32 +1,29 @@
-use crate::infer::{InferCtxt, TyOrConstInferVar};
-use crate::traits::normalize::normalize_with_depth_to;
+use std::marker::PhantomData;
+
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::obligation_forest::ProcessResult;
-use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
-use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
+use rustc_data_structures::obligation_forest::{
+    Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult,
+};
 use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_infer::traits::{FromSolverError, ProjectionCacheKey};
-use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
+use rustc_infer::traits::{
+    FromSolverError, PolyTraitObligation, ProjectionCacheKey, SelectionError, TraitEngine,
+};
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Binder, Const, TypeVisitableExt};
-use std::marker::PhantomData;
+use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
 
 use super::project::{self, ProjectAndUnifyResult};
 use super::select::SelectionContext;
-use super::wf;
-use super::EvaluationResult;
-use super::PredicateObligation;
-use super::Unimplemented;
-use super::{const_evaluatable, ScrubbedTraitError};
-use super::{FulfillmentError, FulfillmentErrorCode};
-
+use super::{
+    const_evaluatable, wf, EvaluationResult, FulfillmentError, FulfillmentErrorCode,
+    PredicateObligation, ScrubbedTraitError, Unimplemented,
+};
 use crate::error_reporting::InferCtxtErrorExt;
-use crate::traits::project::PolyProjectionObligation;
-use crate::traits::project::ProjectionCacheKeyExt as _;
+use crate::infer::{InferCtxt, TyOrConstInferVar};
+use crate::traits::normalize::normalize_with_depth_to;
+use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 
 impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index d749b686803..3e65194577e 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -1,7 +1,6 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
-use crate::regions::InferCtxtRegionExt;
-use crate::traits::{self, FulfillmentError, ObligationCause};
+use std::assert_matches::assert_matches;
 
 use hir::LangItem;
 use rustc_ast::Mutability;
@@ -12,6 +11,8 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
 
 use super::outlives_bounds::InferCtxtExt;
+use crate::regions::InferCtxtRegionExt;
+use crate::traits::{self, FulfillmentError, ObligationCause};
 
 pub enum CopyImplementationError<'tcx> {
     InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
@@ -93,7 +94,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
     lang_item: LangItem,
     parent_cause: ObligationCause<'tcx>,
 ) -> Result<(), ConstParamTyImplementationError<'tcx>> {
-    assert!(matches!(lang_item, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy));
+    assert_matches!(lang_item, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy);
 
     let inner_tys: Vec<_> = match *self_type.kind() {
         // Trivially okay as these types are all:
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index c57ca014799..a350b76a704 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -22,51 +22,55 @@ mod util;
 pub mod vtable;
 pub mod wf;
 
-use crate::error_reporting::InferCtxtErrorExt;
-use crate::infer::outlives::env::OutlivesEnvironment;
-use crate::infer::{InferCtxt, TyCtxtInferExt};
-use crate::regions::InferCtxtRegionExt;
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use std::fmt::Debug;
+use std::ops::ControlFlow;
+
 use rustc_errors::ErrorGuaranteed;
+pub use rustc_infer::traits::*;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast};
-use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::ty::{
+    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast,
+};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
-use std::fmt::Debug;
-use std::ops::ControlFlow;
-
-pub use self::coherence::{add_placeholder_note, orphan_check_trait_ref, overlapping_impls};
-pub use self::coherence::{InCrate, IsFirstInputType, UncoveredTyParams};
-pub use self::coherence::{OrphanCheckErr, OrphanCheckMode, OverlapResult};
+pub use self::coherence::{
+    add_placeholder_note, orphan_check_trait_ref, overlapping_impls, InCrate, IsFirstInputType,
+    OrphanCheckErr, OrphanCheckMode, OverlapResult, UncoveredTyParams,
+};
 pub use self::engine::{ObligationCtxt, TraitEngineExt};
 pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation};
 pub use self::normalize::NormalizeExt;
-pub use self::object_safety::hir_ty_lowering_object_safety_violations;
-pub use self::object_safety::is_vtable_safe_method;
-pub use self::object_safety::object_safety_violations_for_assoc_item;
-pub use self::object_safety::ObjectSafetyViolation;
+pub use self::object_safety::{
+    hir_ty_lowering_object_safety_violations, is_vtable_safe_method,
+    object_safety_violations_for_assoc_item, ObjectSafetyViolation,
+};
 pub use self::project::{normalize_inherent_projection, normalize_projection_ty};
-pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
-pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
-pub use self::specialize::specialization_graph::FutureCompatOverlapError;
-pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
+pub use self::select::{
+    EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache,
+    SelectionContext,
+};
+pub use self::specialize::specialization_graph::{
+    FutureCompatOverlapError, FutureCompatOverlapErrorKind,
+};
 pub use self::specialize::{
     specialization_graph, translate_args, translate_args_with_cause, OverlapError,
 };
 pub use self::structural_normalize::StructurallyNormalizeExt;
-pub use self::util::elaborate;
-pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
-pub use self::util::{impl_item_is_final, upcast_choices};
-pub use self::util::{supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item};
-pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
-
-pub use rustc_infer::traits::*;
+pub use self::util::{
+    elaborate, expand_trait_aliases, impl_item_is_final, supertraits,
+    transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars,
+    BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo,
+};
+use crate::error_reporting::InferCtxtErrorExt;
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::{InferCtxt, TyCtxtInferExt};
+use crate::regions::InferCtxtRegionExt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 pub struct FulfillmentError<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 26cb9bb5a3d..81f8633ba95 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -1,20 +1,24 @@
 //! Deeply normalize types using the old trait solver.
 
-use super::SelectionContext;
-use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
-use crate::error_reporting::traits::OverflowCause;
-use crate::error_reporting::InferCtxtErrorExt;
-use crate::solve::NextSolverError;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
 use rustc_infer::infer::InferOk;
-use rustc_infer::traits::FromSolverError;
-use rustc_infer::traits::PredicateObligation;
-use rustc_infer::traits::{Normalized, Obligation, TraitEngine};
+use rustc_infer::traits::{
+    FromSolverError, Normalized, Obligation, PredicateObligation, TraitEngine,
+};
 use rustc_macros::extension;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder};
-use rustc_middle::ty::{TypeFoldable, TypeSuperFoldable, TypeVisitable, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt,
+};
+
+use super::{
+    project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer,
+    SelectionContext,
+};
+use crate::error_reporting::traits::OverflowCause;
+use crate::error_reporting::InferCtxtErrorExt;
+use crate::solve::NextSolverError;
 
 #[extension(pub trait NormalizeExt<'tcx>)]
 impl<'tcx> At<'_, 'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index ec19cf27668..8e1fc0d7fe6 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -8,11 +8,9 @@
 //!   - not reference the erased type `Self` except for in this receiver;
 //!   - not have generic type parameters.
 
-use super::elaborate;
+use std::iter;
+use std::ops::ControlFlow;
 
-use crate::infer::TyCtxtInferExt;
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::{util, Obligation, ObligationCause};
 use rustc_errors::FatalError;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -27,9 +25,10 @@ use rustc_span::Span;
 use rustc_target::abi::Abi;
 use smallvec::SmallVec;
 
-use std::iter;
-use std::ops::ControlFlow;
-
+use super::elaborate;
+use crate::infer::TyCtxtInferExt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{util, Obligation, ObligationCause};
 pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
 
 /// Returns the object safety violations that affect HIR ty lowering.
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 1dc2ebfaa7a..0fe75059904 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -1,15 +1,15 @@
-use crate::infer::InferCtxt;
-use crate::traits::{ObligationCause, ObligationCtxt};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::infer::InferOk;
 use rustc_macros::extension;
 use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
 use rustc_middle::span_bug;
+pub use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::LocalDefId;
 
-pub use rustc_middle::traits::query::OutlivesBound;
+use crate::infer::InferCtxt;
+use crate::traits::{ObligationCause, ObligationCtxt};
 
 pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
 pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b96e0c8a977..8a17d7ed641 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2,29 +2,6 @@
 
 use std::ops::ControlFlow;
 
-use super::specialization_graph;
-use super::translate_args;
-use super::util;
-use super::MismatchedProjectionTypes;
-use super::Obligation;
-use super::ObligationCause;
-use super::PredicateObligation;
-use super::Selection;
-use super::SelectionContext;
-use super::SelectionError;
-use super::{Normalized, NormalizedTerm, ProjectionCacheEntry, ProjectionCacheKey};
-use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::traits::BuiltinImplSource;
-use rustc_middle::traits::ImplSource;
-use rustc_middle::traits::ImplSourceUserDefinedData;
-use rustc_middle::{bug, span_bug};
-
-use crate::errors::InherentProjectionNormalizationOverflow;
-use crate::infer::{BoundRegionConversionTime, InferOk};
-use crate::traits::normalize::normalize_with_depth;
-use crate::traits::normalize::normalize_with_depth_to;
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::select::ProjectionMatchesProjection;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorGuaranteed;
@@ -32,13 +9,26 @@ use rustc_hir::def::DefKind;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::infer::DefineOpaqueTypes;
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::select::OverflowError;
+pub use rustc_middle::traits::Reveal;
+use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 
-pub use rustc_middle::traits::Reveal;
+use super::{
+    specialization_graph, translate_args, util, MismatchedProjectionTypes, Normalized,
+    NormalizedTerm, Obligation, ObligationCause, PredicateObligation, ProjectionCacheEntry,
+    ProjectionCacheKey, Selection, SelectionContext, SelectionError,
+};
+use crate::errors::InherentProjectionNormalizationOverflow;
+use crate::infer::{BoundRegionConversionTime, InferOk};
+use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::select::ProjectionMatchesProjection;
 
 pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
 
@@ -1120,7 +1110,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Error(_) => false,
                     }
                 } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) {
-                    let tail = selcx.tcx().struct_tail_with_normalize(
+                    let tail = selcx.tcx().struct_tail_raw(
                         self_ty,
                         |ty| {
                             // We throw away any obligations we get from this, since we normalize
@@ -1159,10 +1149,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Never
                         // Extern types have unit metadata, according to RFC 2850
                         | ty::Foreign(_)
-                        // If returned by `struct_tail_without_normalization` this is a unit struct
+                        // If returned by `struct_tail` this is a unit struct
                         // without any fields, or not a struct, and therefore is Sized.
                         | ty::Adt(..)
-                        // If returned by `struct_tail_without_normalization` this is the empty tuple.
+                        // If returned by `struct_tail` this is the empty tuple.
                         | ty::Tuple(..)
                         // Integers and floats are always Sized, and so have unit type metadata.
                         | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 7dc051e6fe9..d3a1ed52d2e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -1,12 +1,12 @@
-use crate::traits::query::normalize::QueryNormalizeExt;
-use crate::traits::query::NoSolution;
-use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
 use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
 use rustc_span::{Span, DUMMY_SP};
 
+use crate::traits::query::normalize::QueryNormalizeExt;
+use crate::traits::query::NoSolution;
+use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
+
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
 /// outlive. This is similar but not *quite* the same as the
@@ -42,8 +42,15 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Foreign(..)
         | ty::Error(_) => true,
 
-        // `T is PAT`, `[T; N]`, and `[T]` have same properties as T.
-        ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
+        // `T is PAT` and `[T]` have same properties as T.
+        ty::Pat(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
+        ty::Array(ty, size) => {
+            // Empty array never has a dtor. See issue #110288.
+            match size.try_to_target_usize(tcx) {
+                Some(0) => true,
+                _ => trivial_dropck_outlives(tcx, *ty),
+            }
+        }
 
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *all* of them are trivial.
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 75f1af7fcf5..247b6e4823c 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -2,26 +2,26 @@
 //! which folds deeply, invoking the underlying
 //! `normalize_canonicalized_projection_ty` query when it encounters projections.
 
-use crate::error_reporting::traits::OverflowCause;
-use crate::error_reporting::InferCtxtErrorExt;
-use crate::infer::at::At;
-use crate::infer::canonical::OriginalQueryValues;
-use crate::infer::{InferCtxt, InferOk};
-use crate::traits::normalize::needs_normalization;
-use crate::traits::Normalized;
-use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
-use crate::traits::{ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_macros::extension;
+pub use rustc_middle::traits::query::NormalizationResult;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
 use rustc_span::DUMMY_SP;
 
 use super::NoSolution;
-
-pub use rustc_middle::traits::query::NormalizationResult;
+use crate::error_reporting::traits::OverflowCause;
+use crate::error_reporting::InferCtxtErrorExt;
+use crate::infer::at::At;
+use crate::infer::canonical::OriginalQueryValues;
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::normalize::needs_normalization;
+use crate::traits::{
+    BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, PredicateObligation,
+    Reveal, ScrubbedTraitError,
+};
 
 #[extension(pub trait QueryNormalizeExt<'tcx>)]
 impl<'cx, 'tcx> At<'cx, 'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index aca16950223..5e4de43d04f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -1,14 +1,14 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_infer::traits::Obligation;
+pub use rustc_middle::traits::query::type_op::AscribeUserType;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, UserType};
-
-pub use rustc_middle::traits::query::type_op::AscribeUserType;
 use rustc_span::{Span, DUMMY_SP};
 
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
+use crate::traits::ObligationCtxt;
+
 impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
     type QueryResponse = ();
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index d533e69a4fa..34e678e93d1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,14 +1,15 @@
-use crate::infer::canonical::query_response;
-use crate::infer::InferCtxt;
-use crate::traits::query::type_op::TypeOpOutput;
-use crate::traits::ObligationCtxt;
+use std::fmt;
+
 use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{TyCtxt, TypeFoldable};
 use rustc_span::Span;
 
-use std::fmt;
+use crate::infer::canonical::query_response;
+use crate::infer::InferCtxt;
+use crate::traits::query::type_op::TypeOpOutput;
+use crate::traits::ObligationCtxt;
 
 pub struct CustomTypeOp<F> {
     closure: F,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
index 57e649f3e43..656130cda19 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
@@ -1,10 +1,10 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
+pub use rustc_middle::traits::query::type_op::Eq;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
-pub use rustc_middle::traits::query::type_op::Eq;
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
+use crate::traits::ObligationCtxt;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
     type QueryResponse = ();
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 8525215a3bc..b5b209c1af7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,7 +1,3 @@
-use crate::traits::query::NoSolution;
-use crate::traits::wf;
-use crate::traits::ObligationCtxt;
-
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::query::OutlivesBound;
@@ -14,6 +10,9 @@ use rustc_span::DUMMY_SP;
 use rustc_type_ir::outlives::{push_outlives_components, Component};
 use smallvec::{smallvec, SmallVec};
 
+use crate::traits::query::NoSolution;
+use crate::traits::{wf, ObligationCtxt};
+
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct ImpliedOutlivesBounds<'tcx> {
     pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index c1b1bfd300b..2f64ed963f9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -1,8 +1,5 @@
-use crate::infer::canonical::{
-    Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
-};
-use crate::infer::{InferCtxt, InferOk};
-use crate::traits::{ObligationCause, ObligationCtxt};
+use std::fmt;
+
 use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::canonical::Certainty;
 use rustc_infer::traits::PredicateObligation;
@@ -10,7 +7,12 @@ use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use rustc_span::Span;
-use std::fmt;
+
+use crate::infer::canonical::{
+    Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
+};
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::{ObligationCause, ObligationCtxt};
 
 pub mod ascribe_user_type;
 pub mod custom;
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index e9948bf1f71..41c34f6da29 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -1,12 +1,13 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
+use std::fmt;
+
+pub use rustc_middle::traits::query::type_op::Normalize;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
-use std::fmt;
 
-pub use rustc_middle::traits::query::type_op::Normalize;
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
+use crate::traits::ObligationCtxt;
 
 impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
 where
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 3e7aa52dcfe..49d324fa62e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -1,11 +1,12 @@
+use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
+use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
+use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
+
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::dropck_outlives::{
     compute_dropck_outlives_inner, trivial_dropck_outlives,
 };
 use crate::traits::ObligationCtxt;
-use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
-use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
-use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct DropckOutlives<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 63289746f5e..294c6bfc124 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -1,11 +1,11 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
 use rustc_infer::traits::Obligation;
+pub use rustc_middle::traits::query::type_op::ProvePredicate;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
 
-pub use rustc_middle::traits::query::type_op::ProvePredicate;
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
+use crate::traits::ObligationCtxt;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
     type QueryResponse = ();
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
index ae11b0825bd..892c2a1f113 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
@@ -1,10 +1,10 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
+pub use rustc_middle::traits::query::type_op::Subtype;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
-pub use rustc_middle::traits::query::type_op::Subtype;
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
+use crate::traits::ObligationCtxt;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
     type QueryResponse = ();
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 06b79ea63ca..9de62031311 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -12,20 +12,17 @@ use hir::def_id::DefId;
 use hir::LangItem;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir as hir;
-use rustc_infer::traits::ObligationCause;
-use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
+use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation, SelectionError};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 
+use super::SelectionCandidate::*;
+use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack};
 use crate::traits;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::util;
 
-use super::BuiltinImplConditions;
-use super::SelectionCandidate::*;
-use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack};
-
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     #[instrument(skip(self, stack), level = "debug")]
     pub(super) fn assemble_candidates<'o>(
@@ -470,8 +467,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
                 candidates.vec.push(AsyncClosureCandidate);
             }
-            ty::FnDef(..) | ty::FnPtr(..) => {
-                candidates.vec.push(AsyncClosureCandidate);
+            // Provide an impl, but only for suitable `fn` pointers.
+            ty::FnPtr(sig) => {
+                if sig.is_fn_trait_compatible() {
+                    candidates.vec.push(AsyncClosureCandidate);
+                }
+            }
+            // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
+            ty::FnDef(def_id, _) => {
+                let tcx = self.tcx();
+                if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+                    && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+                {
+                    candidates.vec.push(AsyncClosureCandidate);
+                }
             }
             _ => {}
         }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 9508a3e8e15..ddd8b970cc8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -7,11 +7,13 @@
 //! [rustc dev guide]:
 //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
 
+use std::iter;
+use std::ops::ControlFlow;
+
 use rustc_ast::Mutability;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::HigherRankedType;
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
 use rustc_middle::ty::{
@@ -21,6 +23,8 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 
+use super::SelectionCandidate::{self, *};
+use super::{BuiltinImplConditions, SelectionContext};
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::util::{self, closure_trait_ref_and_return_type};
 use crate::traits::{
@@ -29,13 +33,6 @@ use crate::traits::{
     SignatureMismatch, TraitNotObjectSafe, TraitObligation, Unimplemented,
 };
 
-use super::BuiltinImplConditions;
-use super::SelectionCandidate::{self, *};
-use super::SelectionContext;
-
-use std::iter;
-use std::ops::ControlFlow;
-
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     pub(super) fn confirm_candidate(
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 699c05466bd..1b2767a6a62 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2,31 +2,12 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
-use self::EvaluationResult::*;
-use self::SelectionCandidate::*;
-
-use super::coherence::{self, Conflict};
-use super::const_evaluatable;
-use super::project;
-use super::project::ProjectionTermObligation;
-use super::util;
-use super::util::closure_trait_ref_and_return_type;
-use super::wf;
-use super::{
-    ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow,
-    PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult,
-    TraitQueryMode,
-};
+use std::cell::{Cell, RefCell};
+use std::fmt::{self, Display};
+use std::ops::ControlFlow;
+use std::{cmp, iter};
 
-use crate::error_reporting::InferCtxtErrorExt;
-use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
-use crate::solve::InferCtxtSelectExt as _;
-use crate::traits::normalize::normalize_with_depth;
-use crate::traits::normalize::normalize_with_depth_to;
-use crate::traits::project::ProjectAndUnifyResult;
-use crate::traits::project::ProjectionCacheKeyExt;
-use crate::traits::ProjectionCacheKey;
-use crate::traits::Unimplemented;
+use hir::def::DefKind;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diag, EmissionGuarantee};
@@ -34,31 +15,39 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_infer::infer::relate::TypeRelation;
-use rustc_infer::infer::BoundRegionConversionTime;
-use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
+use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::bug;
-use rustc_middle::dep_graph::dep_kinds;
-use rustc_middle::dep_graph::DepNodeIndex;
+use rustc_middle::dep_graph::{dep_kinds, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
+pub use rustc_middle::traits::select::*;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::TypeErrorToStringExt;
-use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast};
-use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
+use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
+use rustc_middle::ty::{
+    self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
+    Upcast,
+};
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 
-use std::cell::{Cell, RefCell};
-use std::cmp;
-use std::fmt::{self, Display};
-use std::iter;
-use std::ops::ControlFlow;
-
-pub use rustc_middle::traits::select::*;
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use self::EvaluationResult::*;
+use self::SelectionCandidate::*;
+use super::coherence::{self, Conflict};
+use super::project::ProjectionTermObligation;
+use super::util::closure_trait_ref_and_return_type;
+use super::{
+    const_evaluatable, project, util, wf, ImplDerivedCause, Normalized, Obligation,
+    ObligationCause, ObligationCauseCode, Overflow, PolyTraitObligation, PredicateObligation,
+    Selection, SelectionError, SelectionResult, TraitQueryMode,
+};
+use crate::error_reporting::InferCtxtErrorExt;
+use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
+use crate::solve::InferCtxtSelectExt as _;
+use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
+use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
+use crate::traits::{ProjectionCacheKey, Unimplemented};
 
 mod _match;
 mod candidate_assembly;
@@ -2810,6 +2799,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             });
         }
 
+        // Register any outlives obligations from the trait here, cc #124336.
+        if matches!(tcx.def_kind(def_id), DefKind::Impl { of_trait: true }) {
+            for clause in tcx.impl_super_outlives(def_id).iter_instantiated(tcx, args) {
+                let clause = normalize_with_depth_to(
+                    self,
+                    param_env,
+                    cause.clone(),
+                    recursion_depth,
+                    clause,
+                    &mut obligations,
+                );
+                obligations.push(Obligation {
+                    cause: cause.clone(),
+                    recursion_depth,
+                    param_env,
+                    predicate: clause.as_predicate(),
+                });
+            }
+        }
+
         obligations
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 3c33d13567d..4c8c5a2eb17 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -10,28 +10,25 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
 pub mod specialization_graph;
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::codes::*;
+use rustc_errors::{Diag, EmissionGuarantee};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::DefineOpaqueTypes;
+use rustc_middle::bug;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
+use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
+use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
+use rustc_span::{sym, ErrorGuaranteed, Span, DUMMY_SP};
 use specialization_graph::GraphExt;
 
+use super::{util, SelectionContext};
 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::{coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{codes::*, Diag, EmissionGuarantee};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::bug;
-use rustc_middle::query::LocalCrate;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
-use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
-use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
-use rustc_span::{sym, ErrorGuaranteed, Span, DUMMY_SP};
-
-use super::util;
-use super::SelectionContext;
 
 /// Information pertinent to an overlapping impl error.
 #[derive(Debug)]
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 90f2c7ad213..732f1b0a3d7 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -1,14 +1,13 @@
-use super::OverlapError;
-
-use crate::traits;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::extension;
 use rustc_middle::bug;
+pub use rustc_middle::traits::specialization_graph::*;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 
-pub use rustc_middle::traits::specialization_graph::*;
+use super::OverlapError;
+use crate::traits;
 
 #[derive(Copy, Clone, Debug)]
 pub enum FutureCompatOverlapErrorKind {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 951af4b0920..52f87699b16 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,19 +1,19 @@
 use std::collections::BTreeMap;
 
-use super::NormalizeExt;
-use super::{ObligationCause, PredicateObligation, SelectionContext};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Diag;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{InferCtxt, InferOk};
+pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt, Upcast};
-use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, Upcast,
+};
 use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
 
-pub use rustc_infer::traits::util::*;
+use super::{NormalizeExt, ObligationCause, PredicateObligation, SelectionContext};
 
 ///////////////////////////////////////////////////////////////////////////
 // `TraitAliasExpander` iterator
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 4645d828461..1729d8d307a 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -1,16 +1,18 @@
-use crate::errors::DumpVTableEntries;
-use crate::traits::{impossible_predicates, is_vtable_safe_method};
+use std::fmt::Debug;
+use std::ops::ControlFlow;
+
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
-use rustc_middle::ty::{GenericArgs, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
+};
 use rustc_span::{sym, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
-use std::fmt::Debug;
-use std::ops::ControlFlow;
+use crate::errors::DumpVTableEntries;
+use crate::traits::{impossible_predicates, is_vtable_safe_method};
 
 #[derive(Clone, Debug)]
 pub enum VtblSegment<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index e77a05dd8e6..7e5fe7e3c94 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -1,17 +1,18 @@
-use crate::infer::InferCtxt;
-use crate::traits;
+use std::iter;
+
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
-use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::{Span, DUMMY_SP};
 
-use std::iter;
+use crate::infer::InferCtxt;
+use crate::traits;
 /// Returns the set of obligations needed to make `arg` well-formed.
 /// If `arg` contains unresolved inference variables, this may include
 /// further WF obligations. However, if `arg` IS an unresolved
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 55abd6098ec..add7ec50a1e 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -5,8 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{GenericArgs, TyCtxt};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::dropck_outlives::{
     compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index fdeda34d294..697c8391803 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -12,11 +12,10 @@ mod normalize_erasing_regions;
 mod normalize_projection_ty;
 mod type_op;
 
+use rustc_middle::query::Providers;
 pub use rustc_trait_selection::traits::query::type_op::ascribe_user_type::type_op_ascribe_user_type_with_span;
 pub use type_op::type_op_prove_predicate_with_cause;
 
-use rustc_middle::query::Providers;
-
 pub fn provide(p: &mut Providers) {
     dropck_outlives::provide(p);
     evaluate_obligation::provide(p);
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 06cd6389efc..0dff4751262 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -4,9 +4,8 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::{
-    normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
-};
+use rustc_trait_selection::traits::query::normalize::NormalizationResult;
+use rustc_trait_selection::traits::query::{CanonicalAliasGoal, NoSolution};
 use rustc_trait_selection::traits::{self, ObligationCause, ScrubbedTraitError, SelectionContext};
 use tracing::debug;
 
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index b6a59a4ad3a..5affadaac38 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -1,9 +1,10 @@
+use std::fmt;
+
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{Clause, ParamEnvAnd};
-use rustc_middle::ty::{FnSig, PolyFnSig, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
@@ -14,7 +15,6 @@ use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
 use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
 use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
 use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
-use std::fmt;
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
index 3378d1c6754..58bd517d7e8 100644
--- a/compiler/rustc_transmute/src/layout/dfa.rs
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -1,9 +1,11 @@
-use super::{nfa, Byte, Nfa, Ref};
-use crate::Map;
 use std::fmt;
 use std::sync::atomic::{AtomicU32, Ordering};
+
 use tracing::instrument;
 
+use super::{nfa, Byte, Nfa, Ref};
+use crate::Map;
+
 #[derive(PartialEq, Clone, Debug)]
 pub(crate) struct Dfa<R>
 where
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index 0377ed5d4c5..bbf155581f9 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -60,9 +60,10 @@ impl Ref for ! {
 
 #[cfg(feature = "rustc")]
 pub mod rustc {
+    use std::fmt::{self, Write};
+
     use rustc_middle::mir::Mutability;
     use rustc_middle::ty::{self, Ty};
-    use std::fmt::{self, Write};
 
     /// A reference in the layout.
     #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
index 3c5963202c6..5db5a8f222d 100644
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -1,8 +1,9 @@
-use super::{Byte, Ref, Tree, Uninhabited};
-use crate::{Map, Set};
 use std::fmt;
 use std::sync::atomic::{AtomicU32, Ordering};
 
+use super::{Byte, Ref, Tree, Uninhabited};
+use crate::{Map, Set};
+
 /// A non-deterministic finite automaton (NFA) that represents the layout of a type.
 /// The transmutability of two given types is computed by comparing their `Nfa`s.
 #[derive(PartialEq, Debug)]
@@ -86,6 +87,7 @@ where
     pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
         Ok(match tree {
             Tree::Byte(b) => Self::from_byte(b),
+            #[cfg(bootstrap)]
             Tree::Def(..) => unreachable!(),
             Tree::Ref(r) => Self::from_ref(r),
             Tree::Alt(alts) => {
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 865f9487213..5c25f913ffe 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -1,6 +1,7 @@
-use super::{Byte, Def, Ref};
 use std::ops::ControlFlow;
 
+use super::{Byte, Def, Ref};
+
 #[cfg(test)]
 mod tests;
 
@@ -170,24 +171,14 @@ where
 
 #[cfg(feature = "rustc")]
 pub(crate) mod rustc {
+    use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf};
+    use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
+    use rustc_span::ErrorGuaranteed;
+    use rustc_target::abi::{FieldsShape, Size, TyAndLayout, Variants};
+
     use super::Tree;
     use crate::layout::rustc::{Def, Ref};
 
-    use rustc_middle::ty::layout::HasTyCtxt;
-    use rustc_middle::ty::layout::LayoutCx;
-    use rustc_middle::ty::layout::LayoutError;
-    use rustc_middle::ty::layout::LayoutOf;
-    use rustc_middle::ty::AdtDef;
-    use rustc_middle::ty::AdtKind;
-    use rustc_middle::ty::List;
-    use rustc_middle::ty::ScalarInt;
-    use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-    use rustc_span::ErrorGuaranteed;
-    use rustc_target::abi::FieldsShape;
-    use rustc_target::abi::Size;
-    use rustc_target::abi::TyAndLayout;
-    use rustc_target::abi::Variants;
-
     #[derive(Debug, Copy, Clone)]
     pub(crate) enum Err {
         /// The layout of the type is not yet supported.
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index 2b052412e6b..31664ee6c4f 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -79,19 +79,15 @@ pub enum Reason<T> {
 
 #[cfg(feature = "rustc")]
 mod rustc {
-    use super::*;
-
     use rustc_hir::lang_items::LangItem;
     use rustc_infer::infer::InferCtxt;
     use rustc_macros::TypeVisitable;
     use rustc_middle::traits::ObligationCause;
-    use rustc_middle::ty::Const;
-    use rustc_middle::ty::ParamEnv;
-    use rustc_middle::ty::Ty;
-    use rustc_middle::ty::TyCtxt;
-    use rustc_middle::ty::ValTree;
+    use rustc_middle::ty::{Const, ParamEnv, Ty, TyCtxt, ValTree};
     use rustc_span::DUMMY_SP;
 
+    use super::*;
+
     /// The source and destination types of a transmutation.
     #[derive(TypeVisitable, Debug, Clone, Copy)]
     pub struct Types<'tcx> {
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index dee5a72c3bc..7c66a827db9 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -4,11 +4,9 @@ pub(crate) mod query_context;
 #[cfg(test)]
 mod tests;
 
-use crate::{
-    layout::{self, dfa, Byte, Def, Dfa, Nfa, Ref, Tree, Uninhabited},
-    maybe_transmutable::query_context::QueryContext,
-    Answer, Condition, Map, Reason,
-};
+use crate::layout::{self, dfa, Byte, Def, Dfa, Nfa, Ref, Tree, Uninhabited};
+use crate::maybe_transmutable::query_context::QueryContext;
+use crate::{Answer, Condition, Map, Reason};
 
 pub(crate) struct MaybeTransmutableQuery<L, C>
 where
@@ -32,15 +30,12 @@ where
 // FIXME: Nix this cfg, so we can write unit tests independently of rustc
 #[cfg(feature = "rustc")]
 mod rustc {
+    use rustc_middle::ty::layout::{LayoutCx, LayoutOf};
+    use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+
     use super::*;
     use crate::layout::tree::rustc::Err;
 
-    use rustc_middle::ty::layout::LayoutCx;
-    use rustc_middle::ty::layout::LayoutOf;
-    use rustc_middle::ty::ParamEnv;
-    use rustc_middle::ty::Ty;
-    use rustc_middle::ty::TyCtxt;
-
     impl<'tcx> MaybeTransmutableQuery<Ty<'tcx>, TyCtxt<'tcx>> {
         /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
         /// then computes an answer using those trees.
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
index 1ccb6f36c8e..95373916a71 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
@@ -34,9 +34,10 @@ pub(crate) mod test {
 
 #[cfg(feature = "rustc")]
 mod rustc {
-    use super::*;
     use rustc_middle::ty::{Ty, TyCtxt};
 
+    use super::*;
+
     impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
         type Def = layout::rustc::Def<'tcx>;
         type Ref = layout::rustc::Ref<'tcx>;
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
index 9c7abf1cbd6..c3be4203cce 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
@@ -1,12 +1,12 @@
+use itertools::Itertools;
+
 use super::query_context::test::{Def, UltraMinimal};
 use crate::maybe_transmutable::MaybeTransmutableQuery;
 use crate::{layout, Reason};
-use itertools::Itertools;
 
 mod safety {
-    use crate::Answer;
-
     use super::*;
+    use crate::Answer;
 
     type Tree = layout::Tree<Def, !>;
 
@@ -63,9 +63,8 @@ mod safety {
 }
 
 mod bool {
-    use crate::Answer;
-
     use super::*;
+    use crate::Answer;
 
     #[test]
     fn should_permit_identity_transmutation_tree() {
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 1dced9cf7cd..d90c3bedc70 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -1,3 +1,5 @@
+use std::iter;
+
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::bug;
@@ -16,8 +18,6 @@ use rustc_target::abi::*;
 use rustc_target::spec::abi::Abi as SpecAbi;
 use tracing::debug;
 
-use std::iter;
-
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
 }
@@ -549,7 +549,7 @@ fn fn_abi_sanity_check<'tcx>(
                 // With metadata. Must be unsized and not on the stack.
                 assert!(arg.layout.is_unsized() && !on_stack);
                 // Also, must not be `extern` type.
-                let tail = cx.tcx.struct_tail_with_normalize(arg.layout.ty, |ty| ty, || {});
+                let tail = cx.tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
                 if matches!(tail.kind(), ty::Foreign(..)) {
                     // These types do not have metadata, so having `meta_attrs` is bogus.
                     // Conceptually, unsized arguments must be copied around, which requires dynamically
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 58f812fc7cf..24926883523 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -1,20 +1,19 @@
+use std::iter;
+
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::bug;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::query::Providers;
 use rustc_middle::thir::visit;
 use rustc_middle::thir::visit::Visitor;
 use rustc_middle::ty::abstract_const::CastKind;
 use rustc_middle::ty::{self, Expr, TyCtxt, TypeVisitableExt};
-use rustc_middle::{mir, thir};
+use rustc_middle::{bug, mir, thir};
 use rustc_span::Span;
 use rustc_target::abi::{VariantIdx, FIRST_VARIANT};
 use tracing::{debug, instrument};
 
-use std::iter;
-
 use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub};
 
 /// Destructures array, ADT or tuple constants into the constants
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 6f71951b516..8812260b3af 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -1,3 +1,5 @@
+use std::iter;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -6,7 +8,6 @@ use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
-use std::iter;
 
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index a2bed61a7ae..43e49138709 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -6,8 +6,7 @@ use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
 use rustc_middle::ty::util::AsyncDropGlueMorphology;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt};
 use rustc_span::sym;
 use rustc_trait_selection::traits;
 use rustc_type_ir::ClosureKind;
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 6045abc50a9..244a6afcf97 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -1,3 +1,6 @@
+use std::fmt::Debug;
+use std::iter;
+
 use hir::def_id::DefId;
 use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
@@ -19,9 +22,6 @@ use rustc_span::symbol::Symbol;
 use rustc_target::abi::*;
 use tracing::{debug, instrument, trace};
 
-use std::fmt::Debug;
-use std::iter;
-
 use crate::errors::{
     MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType,
 };
@@ -219,9 +219,13 @@ fn layout_of_uncached<'tcx>(
                             // its struct tail cannot be normalized either, so try to get a
                             // more descriptive layout error here, which will lead to less confusing
                             // diagnostics.
+                            //
+                            // We use the raw struct tail function here to get the first tail
+                            // that is an alias, which is likely the cause of the normalization
+                            // error.
                             match tcx.try_normalize_erasing_regions(
                                 param_env,
-                                tcx.struct_tail_without_normalization(pointee),
+                                tcx.struct_tail_raw(pointee, |ty| ty, || {}),
                             ) {
                                 Ok(_) => {}
                                 Err(better_err) => {
@@ -244,7 +248,7 @@ fn layout_of_uncached<'tcx>(
 
                 metadata
             } else {
-                let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
+                let unsized_part = tcx.struct_tail_for_codegen(pointee, param_env);
 
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
@@ -733,9 +737,7 @@ fn coroutine_saved_local_eligibility(
                     // point, so it is no longer a candidate.
                     trace!(
                         "removing local {:?} in >1 variant ({:?}, {:?})",
-                        local,
-                        variant_index,
-                        idx
+                        local, variant_index, idx
                     );
                     ineligible_locals.insert(*local);
                     assignments[*local] = Ineligible(None);
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index ab7d1be226b..2223aca28d1 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -1,12 +1,10 @@
+use std::assert_matches::assert_matches;
+
 use rustc_middle::bug;
-use rustc_middle::ty::{
-    layout::{LayoutCx, TyAndLayout},
-    TyCtxt,
-};
+use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
+use rustc_middle::ty::TyCtxt;
 use rustc_target::abi::*;
 
-use std::assert_matches::assert_matches;
-
 /// Enforce some basic invariants on layouts.
 pub(super) fn sanity_check_layout<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
@@ -251,7 +249,7 @@ pub(super) fn sanity_check_layout<'tcx>(
     if let Variants::Multiple { variants, .. } = &layout.variants {
         for variant in variants.iter() {
             // No nested "multiple".
-            assert!(matches!(variant.variants, Variants::Single { .. }));
+            assert_matches!(variant.variants, Variants::Single { .. });
             // Variants should have the same or a smaller size as the full thing,
             // and same for alignment.
             if variant.size > layout.size {
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 205b3f2760f..d274a934d52 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -5,8 +5,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt};
 use rustc_session::Limit;
 use rustc_span::sym;
 use tracing::debug;
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 5e91320f897..6680b451b7c 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -1,12 +1,12 @@
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{def::DefKind, def_id::LocalDefId};
 use rustc_hir::{intravisit, CRATE_HIR_ID};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_span::Span;
 use tracing::{instrument, trace};
 
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
index eb6cb369974..568b9383ffb 100644
--- a/compiler/rustc_ty_utils/src/sig_types.rs
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -3,7 +3,8 @@
 
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
-use rustc_hir::{def::DefKind, def_id::LocalDefId};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Span;
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
index 241aff9c30a..1ead7b731e7 100644
--- a/compiler/rustc_ty_utils/src/structural_match.rs
+++ b/compiler/rustc_ty_utils/src/structural_match.rs
@@ -1,8 +1,7 @@
 use rustc_hir::lang_items::LangItem;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 
 /// This method returns true if and only if `adt_ty` itself has been marked as
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 38950c97c9d..aba2acd1842 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -5,8 +5,10 @@ use rustc_hir::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt, TypeVisitor};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, Upcast};
+use rustc_middle::ty::{
+    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    TypeVisitor, Upcast,
+};
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits;
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 7e93dc248cc..d609e5add14 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -1,12 +1,11 @@
-#![allow(clippy::derived_hash_with_manual_eq)]
+use std::fmt;
+use std::hash::Hash;
+use std::ops::Index;
 
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
-use std::fmt;
-use std::hash::Hash;
-use std::ops::Index;
 
 use crate::inherent::*;
 use crate::{self as ty, Interner, UniverseIndex};
@@ -141,7 +140,7 @@ impl<I: Interner> CanonicalVarInfo<I> {
 /// Describes the "kind" of the canonical variable. This is a "kind"
 /// in the type-theory sense of the term -- i.e., a "meta" type system
 /// that analyzes type-like values.
-#[derive_where(Clone, Copy, Hash, Eq, Debug; I: Interner)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum CanonicalVarKind<I: Interner> {
@@ -169,21 +168,6 @@ pub enum CanonicalVarKind<I: Interner> {
     PlaceholderConst(I::PlaceholderConst),
 }
 
-// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
-impl<I: Interner> PartialEq for CanonicalVarKind<I> {
-    fn eq(&self, other: &Self) -> bool {
-        match (self, other) {
-            (Self::Ty(l0), Self::Ty(r0)) => l0 == r0,
-            (Self::PlaceholderTy(l0), Self::PlaceholderTy(r0)) => l0 == r0,
-            (Self::Region(l0), Self::Region(r0)) => l0 == r0,
-            (Self::PlaceholderRegion(l0), Self::PlaceholderRegion(r0)) => l0 == r0,
-            (Self::Const(l0), Self::Const(r0)) => l0 == r0,
-            (Self::PlaceholderConst(l0), Self::PlaceholderConst(r0)) => l0 == r0,
-            _ => std::mem::discriminant(self) == std::mem::discriminant(other),
-        }
-    }
-}
-
 impl<I: Interner> CanonicalVarKind<I> {
     pub fn universe(self) -> UniverseIndex {
         match self {
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index 71f9eb0ef8a..f443f596373 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -1,8 +1,8 @@
-use crate::{Interner, PredicateKind};
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::{SpanDecoder, SpanEncoder};
 
+use crate::{Interner, PredicateKind};
+
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
 /// This offset is also chosen so that the first byte is never < 0x80.
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 458ffdabe94..7a8c612057f 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::derived_hash_with_manual_eq)]
+use std::fmt;
 
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
@@ -6,14 +6,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
-use std::fmt;
 
 use crate::{self as ty, DebruijnIndex, Interner};
 
-use self::ConstKind::*;
-
 /// Represents a constant in Rust.
-#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum ConstKind<I: Interner> {
     /// A const generic parameter.
@@ -45,23 +42,6 @@ pub enum ConstKind<I: Interner> {
     Expr(I::ExprConst),
 }
 
-// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
-impl<I: Interner> PartialEq for ConstKind<I> {
-    fn eq(&self, other: &Self) -> bool {
-        match (self, other) {
-            (Param(l0), Param(r0)) => l0 == r0,
-            (Infer(l0), Infer(r0)) => l0 == r0,
-            (Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1,
-            (Placeholder(l0), Placeholder(r0)) => l0 == r0,
-            (Unevaluated(l0), Unevaluated(r0)) => l0 == r0,
-            (Value(l0, l1), Value(r0, r1)) => l0 == r0 && l1 == r1,
-            (Error(l0), Error(r0)) => l0 == r0,
-            (Expr(l0), Expr(r0)) => l0 == r0,
-            _ => false,
-        }
-    }
-}
-
 impl<I: Interner> fmt::Debug for ConstKind<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         use ConstKind::*;
@@ -80,7 +60,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
 }
 
 /// An unevaluated (potentially generic) constant used in the type-system.
-#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
+#[derive_where(Clone, Copy, Debug, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct UnevaluatedConst<I: Interner> {
@@ -95,15 +75,6 @@ impl<I: Interner> UnevaluatedConst<I> {
     }
 }
 
-impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("UnevaluatedConst")
-            .field("def", &self.def)
-            .field("args", &self.args)
-            .finish()
-    }
-}
-
 rustc_index::newtype_index! {
     /// A **`const`** **v**ariable **ID**.
     #[encodable]
diff --git a/compiler/rustc_type_ir/src/data_structures.rs b/compiler/rustc_type_ir/src/data_structures.rs
index 6d8ab61b722..4ca97c0c86c 100644
--- a/compiler/rustc_type_ir/src/data_structures.rs
+++ b/compiler/rustc_type_ir/src/data_structures.rs
@@ -1,25 +1,20 @@
 #[cfg(feature = "nightly")]
 mod impl_ {
-    pub use rustc_data_structures::fx::FxHashMap as HashMap;
-    pub use rustc_data_structures::fx::FxHashSet as HashSet;
-    pub use rustc_data_structures::fx::FxIndexMap as IndexMap;
-    pub use rustc_data_structures::fx::FxIndexSet as IndexSet;
-    pub use rustc_data_structures::sso::SsoHashMap;
-    pub use rustc_data_structures::sso::SsoHashSet;
+    pub use rustc_data_structures::fx::{
+        FxHashMap as HashMap, FxHashSet as HashSet, FxIndexMap as IndexMap, FxIndexSet as IndexSet,
+    };
+    pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet};
     pub use rustc_data_structures::stack::ensure_sufficient_stack;
     pub use rustc_data_structures::sync::Lrc;
 }
 
 #[cfg(not(feature = "nightly"))]
 mod impl_ {
-    pub use indexmap::IndexMap;
-    pub use indexmap::IndexSet;
-    pub use std::collections::HashMap;
-    pub use std::collections::HashMap as SsoHashMap;
-    pub use std::collections::HashSet;
-    pub use std::collections::HashSet as SsoHashSet;
+    pub use std::collections::{HashMap, HashMap as SsoHashMap, HashSet, HashSet as SsoHashSet};
     pub use std::sync::Arc as Lrc;
 
+    pub use indexmap::{IndexMap, IndexSet};
+
     #[inline]
     pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
         f()
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 7dd2f3de3f8..f30419c801f 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -3,9 +3,9 @@ use std::marker::PhantomData;
 use smallvec::smallvec;
 
 use crate::data_structures::HashSet;
+use crate::inherent::*;
 use crate::outlives::{push_outlives_components, Component};
-use crate::{self as ty, Interner};
-use crate::{inherent::*, Upcast as _};
+use crate::{self as ty, Interner, Upcast as _};
 
 /// "Elaboration" is the process of identifying all the predicates that
 /// are implied by a source predicate. Currently, this basically means
@@ -264,15 +264,6 @@ pub fn supertraits<I: Interner>(
     elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits()
 }
 
-pub fn transitive_bounds<I: Interner>(
-    cx: I,
-    trait_refs: impl Iterator<Item = ty::Binder<I, ty::TraitRef<I>>>,
-) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
-    elaborate(cx, trait_refs.map(|trait_ref| trait_ref.upcast(cx)))
-        .filter_only_self()
-        .filter_to_traits()
-}
-
 impl<I: Interner> Elaborator<I, I::Clause> {
     fn filter_to_traits(self) -> FilterToTraits<I, Self> {
         FilterToTraits { _cx: PhantomData, base_iterator: self }
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index a4d8dafb246..d37bacc7d35 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -45,8 +45,9 @@
 //! - u.fold_with(folder)
 //! ```
 
-use rustc_index::{Idx, IndexVec};
 use std::mem;
+
+use rustc_index::{Idx, IndexVec};
 use tracing::debug;
 
 use crate::data_structures::Lrc;
@@ -90,6 +91,7 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
     fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
         match self.try_fold_with(folder) {
             Ok(t) => t,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
@@ -114,6 +116,7 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
     fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
         match self.try_super_fold_with(folder) {
             Ok(t) => t,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 63ad36efc85..263ba676427 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -432,6 +432,7 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
     + UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>>
     + UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>>
     + IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
+    + Elaboratable<I>
 {
     fn as_clause(self) -> Option<I::Clause>;
 
@@ -450,6 +451,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
     + UpcastFrom<I, ty::TraitRef<I>>
     + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+    + UpcastFrom<I, ty::TraitPredicate<I>>
+    + UpcastFrom<I, ty::Binder<I, ty::TraitPredicate<I>>>
     + UpcastFrom<I, ty::ProjectionPredicate<I>>
     + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
     + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 14ebbb12fe2..c251540c0fc 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -1,22 +1,24 @@
-use rustc_ast_ir::Movability;
-use rustc_index::bit_set::BitSet;
-use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
 
+use rustc_ast_ir::Movability;
+use rustc_index::bit_set::BitSet;
+use smallvec::SmallVec;
+
 use crate::fold::TypeFoldable;
 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::{
     CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
 };
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
-use crate::{self as ty};
+use crate::{
+    search_graph, {self as ty},
+};
 
 pub trait Interner:
     Sized
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 80e970a23a9..de41d2f3cc5 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -9,11 +9,12 @@
 
 extern crate self as rustc_type_ir;
 
-#[cfg(feature = "nightly")]
-use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
 use std::fmt;
 use std::hash::Hash;
 
+#[cfg(feature = "nightly")]
+use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
+
 // These modules are `pub` since they are not glob-imported.
 #[macro_use]
 pub mod visit;
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 70b7c29bdfc..c8a21028588 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -1,16 +1,15 @@
-#![allow(clippy::derived_hash_with_manual_eq)]
+use std::fmt;
 
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
-use std::fmt;
 
 use crate::{self as ty, Interner};
 
 /// A clause is something that can appear in where bounds or be inferred
 /// by implied bounds.
-#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum ClauseKind<I: Interner> {
@@ -40,22 +39,6 @@ pub enum ClauseKind<I: Interner> {
     ConstEvaluatable(I::Const),
 }
 
-// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
-impl<I: Interner> PartialEq for ClauseKind<I> {
-    fn eq(&self, other: &Self) -> bool {
-        match (self, other) {
-            (Self::Trait(l0), Self::Trait(r0)) => l0 == r0,
-            (Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0,
-            (Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0,
-            (Self::Projection(l0), Self::Projection(r0)) => l0 == r0,
-            (Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1,
-            (Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0,
-            (Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0,
-            _ => false,
-        }
-    }
-}
-
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index ef18ef15235..e0b39737007 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -1,15 +1,13 @@
-#![allow(clippy::derived_hash_with_manual_eq)]
+use std::fmt;
 
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
-use std::fmt;
-
-use crate::{DebruijnIndex, Interner};
 
 use self::RegionKind::*;
+use crate::{DebruijnIndex, Interner};
 
 rustc_index::newtype_index! {
     /// A **region** **v**ariable **ID**.
@@ -127,7 +125,7 @@ rustc_index::newtype_index! {
 /// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
 /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
 pub enum RegionKind<I: Interner> {
     /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
@@ -179,48 +177,6 @@ pub enum RegionKind<I: Interner> {
     ReError(I::ErrorGuaranteed),
 }
 
-// This is manually implemented for `RegionKind` because `std::mem::discriminant`
-// returns an opaque value that is `PartialEq` but not `PartialOrd`
-#[inline]
-const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
-    match value {
-        ReEarlyParam(_) => 0,
-        ReBound(_, _) => 1,
-        ReLateParam(_) => 2,
-        ReStatic => 3,
-        ReVar(_) => 4,
-        RePlaceholder(_) => 5,
-        ReErased => 6,
-        ReError(_) => 7,
-    }
-}
-
-// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
-// This is manually implemented because a derive would require `I: PartialEq`
-impl<I: Interner> PartialEq for RegionKind<I> {
-    #[inline]
-    fn eq(&self, other: &RegionKind<I>) -> bool {
-        regionkind_discriminant(self) == regionkind_discriminant(other)
-            && match (self, other) {
-                (ReEarlyParam(a_r), ReEarlyParam(b_r)) => a_r == b_r,
-                (ReBound(a_d, a_r), ReBound(b_d, b_r)) => a_d == b_d && a_r == b_r,
-                (ReLateParam(a_r), ReLateParam(b_r)) => a_r == b_r,
-                (ReStatic, ReStatic) => true,
-                (ReVar(a_r), ReVar(b_r)) => a_r == b_r,
-                (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
-                (ReErased, ReErased) => true,
-                (ReError(_), ReError(_)) => true,
-                _ => {
-                    debug_assert!(
-                        false,
-                        "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
-                    );
-                    true
-                }
-            }
-    }
-}
-
 impl<I: Interner> fmt::Debug for RegionKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index e25df7a0f60..47d5e0dace7 100644
--- a/compiler/rustc_type_ir/src/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -17,14 +17,16 @@
 //!
 //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
 
+use std::fmt::Debug;
+use std::hash::Hash;
+
+use derive_where::derive_where;
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+
 use crate::solve::{
     CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
 };
 use crate::{Canonical, CanonicalVarValues, Interner};
-use derive_where::derive_where;
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
-use std::fmt::Debug;
-use std::hash::Hash;
 
 /// Some `data` together with information about how they relate to the input
 /// of the canonical query.
diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs
index 0e4930552c2..a9995667450 100644
--- a/compiler/rustc_type_ir/src/ty_info.rs
+++ b/compiler/rustc_type_ir/src/ty_info.rs
@@ -1,10 +1,11 @@
+use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+
 #[cfg(feature = "nightly")]
 use rustc_data_structures::fingerprint::Fingerprint;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use std::cmp::Ordering;
-use std::hash::{Hash, Hasher};
-use std::ops::Deref;
 
 use crate::{DebruijnIndex, TypeFlags};
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 4672904ab73..7e48f1b20a8 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -1,7 +1,7 @@
-#![allow(clippy::derived_hash_with_manual_eq)]
+use std::fmt;
 
 use derive_where::derive_where;
-
+use rustc_ast_ir::Mutability;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
@@ -9,15 +9,12 @@ use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
-use std::fmt;
 
 pub use self::closure::*;
 use self::TyKind::*;
 use crate::inherent::*;
 use crate::{self as ty, DebruijnIndex, Interner};
 
-use rustc_ast_ir::Mutability;
-
 mod closure;
 
 /// Specifies how a trait object is represented.
@@ -68,7 +65,7 @@ impl AliasTyKind {
 /// Types written by the user start out as `hir::TyKind` and get
 /// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
 #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
-#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum TyKind<I: Interner> {
     /// The primitive boolean type. Written as `bool`.
@@ -259,92 +256,6 @@ impl<I: Interner> TyKind<I> {
     }
 }
 
-// This is manually implemented for `TyKind` because `std::mem::discriminant`
-// returns an opaque value that is `PartialEq` but not `PartialOrd`
-#[inline]
-const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
-    match value {
-        Bool => 0,
-        Char => 1,
-        Int(_) => 2,
-        Uint(_) => 3,
-        Float(_) => 4,
-        Adt(_, _) => 5,
-        Foreign(_) => 6,
-        Str => 7,
-        Array(_, _) => 8,
-        Slice(_) => 9,
-        RawPtr(_, _) => 10,
-        Ref(_, _, _) => 11,
-        FnDef(_, _) => 12,
-        FnPtr(_) => 13,
-        Dynamic(..) => 14,
-        Closure(_, _) => 15,
-        CoroutineClosure(_, _) => 16,
-        Coroutine(_, _) => 17,
-        CoroutineWitness(_, _) => 18,
-        Never => 19,
-        Tuple(_) => 20,
-        Pat(_, _) => 21,
-        Alias(_, _) => 22,
-        Param(_) => 23,
-        Bound(_, _) => 24,
-        Placeholder(_) => 25,
-        Infer(_) => 26,
-        Error(_) => 27,
-    }
-}
-
-// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
-// This is manually implemented because a derive would require `I: PartialEq`
-impl<I: Interner> PartialEq for TyKind<I> {
-    #[inline]
-    fn eq(&self, other: &TyKind<I>) -> bool {
-        // You might expect this `match` to be preceded with this:
-        //
-        //   tykind_discriminant(self) == tykind_discriminant(other) &&
-        //
-        // but the data patterns in practice are such that a comparison
-        // succeeds 99%+ of the time, and it's faster to omit it.
-        match (self, other) {
-            (Int(a_i), Int(b_i)) => a_i == b_i,
-            (Uint(a_u), Uint(b_u)) => a_u == b_u,
-            (Float(a_f), Float(b_f)) => a_f == b_f,
-            (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
-            (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
-            (Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c,
-            (Slice(a_t), Slice(b_t)) => a_t == b_t,
-            (RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m,
-            (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
-            (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
-            (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
-                a_p == b_p && a_r == b_r && a_repr == b_repr
-            }
-            (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (CoroutineClosure(a_d, a_s), CoroutineClosure(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
-            (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
-            (Param(a_p), Param(b_p)) => a_p == b_p,
-            (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
-            (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
-            (Infer(a_t), Infer(b_t)) => a_t == b_t,
-            (Error(a_e), Error(b_e)) => a_e == b_e,
-            (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
-            _ => {
-                debug_assert!(
-                    tykind_discriminant(self) != tykind_discriminant(other),
-                    "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
-                );
-                false
-            }
-        }
-    }
-}
-
 // This is manually implemented because a derive would require `I: Debug`
 impl<I: Interner> fmt::Debug for TyKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index d5e114b2175..0ba7e2bd552 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -41,11 +41,12 @@
 //! - u.visit_with(visitor)
 //! ```
 
+use std::fmt;
+use std::ops::ControlFlow;
+
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_ast_ir::{try_visit, walk_visitable_list};
 use rustc_index::{Idx, IndexVec};
-use std::fmt;
-use std::ops::ControlFlow;
 
 use crate::data_structures::Lrc;
 use crate::inherent::*;
diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs
index f5b90424afb..2bfbfaa498b 100644
--- a/compiler/rustc_type_ir_macros/src/lib.rs
+++ b/compiler/rustc_type_ir_macros/src/lib.rs
@@ -1,5 +1,6 @@
 use quote::quote;
-use syn::{parse_quote, visit_mut::VisitMut};
+use syn::parse_quote;
+use syn::visit_mut::VisitMut;
 use synstructure::decl_derive;
 
 decl_derive!(
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
index c003ec1fbc9..9d3b40e5eea 100644
--- a/compiler/stable_mir/src/abi.rs
+++ b/compiler/stable_mir/src/abi.rs
@@ -1,14 +1,14 @@
+use std::fmt::{self, Debug};
+use std::num::NonZero;
+use std::ops::RangeInclusive;
+
+use serde::Serialize;
+
 use crate::compiler_interface::with;
-use crate::error;
 use crate::mir::FieldIdx;
 use crate::target::{MachineInfo, MachineSize as Size};
 use crate::ty::{Align, IndexedVal, Ty, VariantIdx};
-use crate::Error;
-use crate::Opaque;
-use serde::Serialize;
-use std::fmt::{self, Debug};
-use std::num::NonZero;
-use std::ops::RangeInclusive;
+use crate::{error, Error, Opaque};
 
 /// A function ABI definition.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs
index bf2b35bf875..2882fdf7bed 100644
--- a/compiler/stable_mir/src/crate_def.rs
+++ b/compiler/stable_mir/src/crate_def.rs
@@ -1,9 +1,10 @@
 //! Module that define a common trait for things that represent a crate definition,
 //! such as, a function, a trait, an enum, and any other definitions.
 
+use serde::Serialize;
+
 use crate::ty::{GenericArgs, Span, Ty};
 use crate::{with, Crate, Symbol};
-use serde::Serialize;
 
 /// A unique identification number for each item accessible for the current compilation unit.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index fe745326d81..b523e949cde 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -17,17 +17,16 @@
 //! The goal is to eventually be published on
 //! [crates.io](https://crates.io).
 
-use std::fmt;
 use std::fmt::Debug;
-use std::io;
+use std::{fmt, io};
+
+use serde::Serialize;
 
 use crate::compiler_interface::with;
 pub use crate::crate_def::{CrateDef, CrateDefType, DefId};
 pub use crate::error::*;
-use crate::mir::Body;
-use crate::mir::Mutability;
+use crate::mir::{Body, Mutability};
 use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
-use serde::Serialize;
 
 pub mod abi;
 #[macro_use]
diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs
index 9e0cac67f0a..a3768f8e01c 100644
--- a/compiler/stable_mir/src/mir/alloc.rs
+++ b/compiler/stable_mir/src/mir/alloc.rs
@@ -1,11 +1,13 @@
 //! This module provides methods to retrieve allocation information, such as static variables.
 
+use std::io::Read;
+
+use serde::Serialize;
+
 use crate::mir::mono::{Instance, StaticDef};
 use crate::target::{Endian, MachineInfo};
 use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
 use crate::{with, Error};
-use serde::Serialize;
-use std::io::Read;
 
 /// An allocation in the SMIR global memory can be either a function pointer,
 /// a static, or a "real" allocation with some data in it.
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index f7457ecd38f..7c09fe1a085 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,3 +1,7 @@
+use std::io;
+
+use serde::Serialize;
+
 use crate::compiler_interface::with;
 use crate::mir::pretty::function_body;
 use crate::ty::{
@@ -5,8 +9,6 @@ use crate::ty::{
     TyConst, TyKind, VariantIdx,
 };
 use crate::{Error, Opaque, Span, Symbol};
-use serde::Serialize;
-use std::io;
 
 /// The SMIR representation of a single function.
 #[derive(Clone, Debug, Serialize)]
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index c23293388f9..cd028444531 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,11 +1,13 @@
+use std::fmt::{Debug, Formatter};
+use std::io;
+
+use serde::Serialize;
+
 use crate::abi::FnAbi;
 use crate::crate_def::CrateDef;
 use crate::mir::Body;
 use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
 use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
-use serde::Serialize;
-use std::fmt::{Debug, Formatter};
-use std::io;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum MonoItem {
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
index 18ecccb4536..dec0068ef7e 100644
--- a/compiler/stable_mir/src/mir/pretty.rs
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -1,14 +1,13 @@
-use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
-use crate::ty::{IndexedVal, MirConst, Ty, TyConst};
-use crate::{with, Body, Mutability};
-use fmt::{Display, Formatter};
 use std::fmt::Debug;
 use std::io::Write;
 use std::{fmt, io, iter};
 
-use super::{AssertMessage, BinOp, TerminatorKind};
+use fmt::{Display, Formatter};
 
-use super::{BorrowKind, FakeBorrowKind};
+use super::{AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
+use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
+use crate::ty::{IndexedVal, MirConst, Ty, TyConst};
+use crate::{with, Body, Mutability};
 
 impl Display for Ty {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs
index 9fb5e046abc..32c3a2a9122 100644
--- a/compiler/stable_mir/src/target.rs
+++ b/compiler/stable_mir/src/target.rs
@@ -1,8 +1,9 @@
 //! Provide information about the machine that this is being compiled into.
 
-use crate::compiler_interface::with;
 use serde::Serialize;
 
+use crate::compiler_interface::with;
+
 /// The properties of the target machine being compiled into.
 #[derive(Clone, PartialEq, Eq, Serialize)]
 pub struct MachineInfo {
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index fb0b8f4d0c3..2f36aa51829 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1,16 +1,16 @@
-use super::{
-    mir::{Body, Mutability, Safety},
-    with, DefId, Error, Symbol,
-};
+use std::fmt::{self, Debug, Display, Formatter};
+use std::ops::Range;
+
+use serde::Serialize;
+
+use super::mir::{Body, Mutability, Safety};
+use super::{with, DefId, Error, Symbol};
 use crate::abi::{FnAbi, Layout};
 use crate::crate_def::{CrateDef, CrateDefType};
 use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
 use crate::mir::mono::StaticDef;
 use crate::target::MachineInfo;
 use crate::{Filename, Opaque};
-use serde::Serialize;
-use std::fmt::{self, Debug, Display, Formatter};
-use std::ops::Range;
 
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)]
 pub struct Ty(usize);
diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs
index fc1da8fafe4..72cf84acb85 100644
--- a/compiler/stable_mir/src/visitor.rs
+++ b/compiler/stable_mir/src/visitor.rs
@@ -1,11 +1,11 @@
 use std::ops::ControlFlow;
 
-use crate::{ty::TyConst, Opaque};
-
 use super::ty::{
     Allocation, Binder, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs,
     MirConst, Promoted, Region, RigidTy, TermKind, Ty, UnevaluatedConst,
 };
+use crate::ty::TyConst;
+use crate::Opaque;
 
 pub trait Visitor: Sized {
     type Break;