about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml1
-rw-r--r--Cargo.lock62
-rw-r--r--RELEASES.md1
-rw-r--r--compiler/rustc_arena/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs8
-rw-r--r--compiler/rustc_ast/src/lib.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs10
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs196
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs172
-rw-r--r--compiler/rustc_borrowck/src/facts.rs3
-rw-r--r--compiler/rustc_borrowck/src/nll.rs42
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs48
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs82
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock166
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml16
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md14
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_backend.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/main.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs67
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/utils.rs35
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt1
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Allow-internal-features.patch24
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch25
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch2
-rw-r--r--compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml72
-rw-r--r--compiler/rustc_codegen_cranelift/patches/rand-lock.toml563
-rw-r--r--compiler/rustc_codegen_cranelift/patches/regex-lock.toml422
-rw-r--r--compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml28
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh18
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/returning.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/analyze.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/cast.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/object.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs23
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs142
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs39
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs39
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs39
-rw-r--r--compiler/rustc_codegen_cranelift/src/pointer.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs10
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/ci.yml18
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/release.yml26
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml24
-rw-r--r--compiler/rustc_codegen_gcc/.gitignore1
-rw-r--r--compiler/rustc_codegen_gcc/Cargo.lock261
-rw-r--r--compiler/rustc_codegen_gcc/Cargo.toml6
-rw-r--r--compiler/rustc_codegen_gcc/Readme.md94
-rwxr-xr-xcompiler/rustc_codegen_gcc/build.sh67
-rw-r--r--compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml2
-rwxr-xr-xcompiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh4
-rwxr-xr-xcompiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh39
-rw-r--r--compiler/rustc_codegen_gcc/build_system/Cargo.lock7
-rw-r--r--compiler/rustc_codegen_gcc/build_system/Cargo.toml8
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/build.rs233
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/config.rs125
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/main.rs62
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/prepare.rs227
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs12
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/utils.rs240
-rw-r--r--compiler/rustc_codegen_gcc/config.sh15
-rw-r--r--compiler/rustc_codegen_gcc/doc/add-attribute.md17
-rw-r--r--compiler/rustc_codegen_gcc/doc/gimple.md111
-rw-r--r--compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md44
-rw-r--r--compiler/rustc_codegen_gcc/example/alloc_example.rs1
-rw-r--r--compiler/rustc_codegen_gcc/example/alloc_system.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs1
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs11
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/mod_bench.rs1
-rw-r--r--compiler/rustc_codegen_gcc/failing-lto-tests.txt23
-rw-r--r--compiler/rustc_codegen_gcc/failing-non-lto-tests.txt11
-rw-r--r--compiler/rustc_codegen_gcc/failing-ui-tests.txt27
-rw-r--r--compiler/rustc_codegen_gcc/failing-ui-tests12.txt1
-rw-r--r--compiler/rustc_codegen_gcc/messages.ftl30
-rw-r--r--compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch19
-rw-r--r--compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch25
-rwxr-xr-xcompiler/rustc_codegen_gcc/prepare.sh30
-rwxr-xr-xcompiler/rustc_codegen_gcc/prepare_build.sh5
-rw-r--r--compiler/rustc_codegen_gcc/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_gcc/rustup.sh2
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs44
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs109
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs102
-rw-r--r--compiler/rustc_codegen_gcc/src/back/lto.rs341
-rw-r--r--compiler/rustc_codegen_gcc/src/back/mod.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/back/write.rs102
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs71
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs29
-rw-r--r--compiler/rustc_codegen_gcc/src/declare.rs40
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs87
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs223
-rw-r--r--compiler/rustc_codegen_gcc/src/int.rs81
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/archs.rs114
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs20
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs192
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs10
-rwxr-xr-xcompiler/rustc_codegen_gcc/test.sh14
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort1.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort2.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/array.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs2
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/assign.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/closure.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/condition.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/empty_main.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/exit.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/exit_code.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/gep.rs10
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/int_overflow.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/mut_ref.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/operations.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/return-tuple.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/slice.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/static.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/structs.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/tuple.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tools/generate_intrinsics.py8
-rwxr-xr-xcompiler/rustc_codegen_gcc/y.sh8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs12
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs23
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs20
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs10
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs101
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/tests.rs45
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs34
-rw-r--r--compiler/rustc_driver_impl/src/session_diagnostics.rs6
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/config.rs162
-rw-r--r--compiler/rustc_feature/src/active.rs69
-rw-r--r--compiler/rustc_feature/src/lib.rs36
-rw-r--r--compiler/rustc_feature/src/removed.rs27
-rw-r--r--compiler/rustc_fluent_macro/src/lib.rs3
-rw-r--r--compiler/rustc_graphviz/src/lib.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs71
-rw-r--r--compiler/rustc_incremental/src/lib.rs3
-rw-r--r--compiler/rustc_index/src/bit_set.rs8
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs508
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs2
-rw-r--r--compiler/rustc_infer/src/lib.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_lint/src/builtin.rs12
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lints.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs17
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp28
-rw-r--r--compiler/rustc_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_log/src/lib.rs11
-rw-r--r--compiler/rustc_metadata/src/creader.rs5
-rw-r--r--compiler/rustc_metadata/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs11
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs6
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs30
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs17
-rw-r--r--compiler/rustc_middle/src/query/keys.rs33
-rw-r--r--compiler/rustc_middle/src/thir.rs13
-rw-r--r--compiler/rustc_middle/src/ty/context.rs25
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs65
-rw-r--r--compiler/rustc_mir_build/messages.ftl2
-rw-r--r--compiler/rustc_mir_build/src/errors.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs85
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs267
-rw-r--r--compiler/rustc_mir_dataflow/src/debuginfo.rs20
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs57
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs116
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs268
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs184
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs22
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs1
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs37
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs3
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs13
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs25
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs79
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs163
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs25
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs141
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs16
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs3
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs13
-rw-r--r--compiler/rustc_passes/src/errors.rs10
-rw-r--r--compiler/rustc_passes/src/lib.rs3
-rw-r--r--compiler/rustc_passes/src/loops.rs55
-rw-r--r--compiler/rustc_plugin_impl/src/lib.rs3
-rw-r--r--compiler/rustc_privacy/src/lib.rs3
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs13
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_serialize/src/collection_impls.rs279
-rw-r--r--compiler/rustc_serialize/src/lib.rs20
-rw-r--r--compiler/rustc_serialize/src/serialize.rs262
-rw-r--r--compiler/rustc_session/Cargo.toml1
-rw-r--r--compiler/rustc_session/src/config.rs154
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs43
-rw-r--r--compiler/rustc_smir/Cargo.toml1
-rw-r--r--compiler/rustc_smir/src/lib.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs72
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs24
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs3
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs99
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs (renamed from compiler/rustc_trait_selection/src/solve/eval_ctxt.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs (renamed from compiler/rustc_trait_selection/src/solve/inherent_projection.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/mod.rs (renamed from compiler/rustc_trait_selection/src/solve/project_goals.rs)4
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs (renamed from compiler/rustc_trait_selection/src/solve/opaques.rs)2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs (renamed from compiler/rustc_trait_selection/src/solve/weak_types.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs (renamed from compiler/rustc_trait_selection/src/solve/search_graph/mod.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs16
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs3
-rw-r--r--compiler/rustc_type_ir/src/structural_impls.rs6
-rw-r--r--compiler/stable_mir/src/lib.rs34
-rw-r--r--compiler/stable_mir/src/ty.rs17
-rw-r--r--library/alloc/src/collections/btree/map.rs2
-rw-r--r--library/alloc/src/collections/btree/set.rs2
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/string.rs150
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/slice/mod.rs56
-rw-r--r--library/core/src/str/iter.rs2
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/slice.rs20
-rw-r--r--library/proc_macro/src/lib.rs2
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/collections/hash/set.rs2
-rw-r--r--library/std/src/io/mod.rs3
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/aix/fs.rs348
-rw-r--r--library/std/src/os/aix/mod.rs6
-rw-r--r--library/std/src/os/aix/raw.rs9
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/sys/unix/args.rs1
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fs.rs35
-rw-r--r--library/std/src/sys/unix/mod.rs1
-rw-r--r--library/std/src/sys/unix/os.rs36
-rw-r--r--library/std/src/sys/unix/thread.rs2
-rw-r--r--library/std/src/sys/unix/thread_local_dtor.rs7
-rw-r--r--library/test/src/lib.rs2
-rw-r--r--library/unwind/src/lib.rs4
-rw-r--r--src/bootstrap/bin/_helper.rs1
-rw-r--r--src/bootstrap/bin/rustc.rs34
-rw-r--r--src/bootstrap/bootstrap.py7
-rw-r--r--src/bootstrap/builder.rs59
-rw-r--r--src/bootstrap/compile.rs10
-rw-r--r--src/bootstrap/dist.rs13
-rw-r--r--src/ci/docker/host-x86_64/dist-various-1/Dockerfile47
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-1/install-mips-musl.sh15
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-1/install-mipsel-musl.sh15
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh2
-rwxr-xr-xsrc/ci/docker/run.sh6
-rw-r--r--src/ci/github-actions/ci.yml1
-rwxr-xr-xsrc/ci/run.sh3
-rwxr-xr-xsrc/ci/scripts/verify-channel.sh2
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/codegen-options/index.md8
-rw-r--r--src/doc/rustc/src/platform-support.md20
-rw-r--r--src/doc/rustdoc/src/unstable-features.md15
-rw-r--r--src/doc/unstable-book/src/language-features/diagnostic-namespace.md84
-rw-r--r--src/librustdoc/clean/mod.rs28
-rw-r--r--src/librustdoc/clean/types.rs14
-rw-r--r--src/librustdoc/clean/utils.rs32
-rw-r--r--src/librustdoc/formats/cache.rs82
-rw-r--r--src/librustdoc/html/format.rs3
-rw-r--r--src/librustdoc/html/layout.rs37
-rw-r--r--src/librustdoc/html/render/context.rs19
-rw-r--r--src/librustdoc/html/render/mod.rs42
-rw-r--r--src/librustdoc/html/render/print_item.rs120
-rw-r--r--src/librustdoc/html/render/search_index.rs33
-rw-r--r--src/librustdoc/html/render/sidebar.rs27
-rw-r--r--src/librustdoc/html/render/write_shared.rs3
-rw-r--r--src/librustdoc/html/sources.rs3
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css86
-rw-r--r--src/librustdoc/html/static/js/main.js68
-rw-r--r--src/librustdoc/html/static/js/search.js19
-rw-r--r--src/librustdoc/html/templates/page.html51
-rw-r--r--src/librustdoc/html/templates/sidebar.html5
-rw-r--r--src/librustdoc/json/conversions.rs18
-rw-r--r--src/librustdoc/lib.rs1
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr2
-rw-r--r--src/tools/compiletest/src/header.rs10
-rw-r--r--src/tools/compiletest/src/header/needs.rs4
-rw-r--r--src/tools/lld-wrapper/src/main.rs4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/machine.rs11
-rw-r--r--src/tools/miri/src/operator.rs78
-rw-r--r--src/tools/miri/tests/pass/float_nan.rs411
-rw-r--r--src/tools/opt-dist/Cargo.toml1
-rw-r--r--src/tools/opt-dist/src/main.rs9
-rw-r--r--src/tools/opt-dist/src/utils/artifact_size.rs61
-rw-r--r--src/tools/opt-dist/src/utils/mod.rs51
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--tests/codegen/debug-fndef-size.rs18
-rw-r--r--tests/incremental/hashes/for_loops.rs6
-rw-r--r--tests/incremental/hashes/loop_expressions.rs4
-rw-r--r--tests/incremental/hashes/while_loops.rs10
-rw-r--r--tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff21
-rw-r--r--tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff24
-rw-r--r--tests/mir-opt/copy-prop/calls.rs43
-rw-r--r--tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff29
-rw-r--r--tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-abort.diff73
-rw-r--r--tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff73
-rw-r--r--tests/mir-opt/dead-store-elimination/cycle.rs37
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir7
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir7
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff2
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff4
-rw-r--r--tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff1
-rw-r--r--tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff1
-rw-r--r--tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir45
-rw-r--r--tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir45
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir45
-rw-r--r--tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir23
-rw-r--r--tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir99
-rw-r--r--tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir46
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir115
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir115
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir64
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir64
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir256
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir14
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir14
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir131
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir131
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir49
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir49
-rw-r--r--tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff22
-rw-r--r--tests/run-make/const_fn_mir/Makefile7
-rw-r--r--tests/run-make/issue-71519/Makefile8
-rw-r--r--tests/run-make/issue-71519/main.rs4
-rw-r--r--tests/run-make/metadata-dep-info/Makefile6
-rw-r--r--tests/run-make/overwrite-input/Makefile10
-rw-r--r--tests/run-make/raw-dylib-alt-calling-convention/Makefile12
-rw-r--r--tests/run-make/raw-dylib-import-name-type/Makefile7
-rw-r--r--tests/run-make/raw-dylib-inline-cross-dylib/Makefile7
-rw-r--r--tests/run-make/raw-dylib-link-ordinal/Makefile7
-rw-r--r--tests/run-make/raw-dylib-stdcall-ordinal/Makefile7
-rw-r--r--tests/run-make/silly-file-names/Makefile6
-rw-r--r--tests/run-make/tools.mk22
-rw-r--r--tests/run-make/unknown-mod-stdin/Makefile11
-rw-r--r--tests/rustdoc-gui/anchors.goml2
-rw-r--r--tests/rustdoc-gui/huge-logo.goml4
-rw-r--r--tests/rustdoc-gui/rust-logo.goml15
-rw-r--r--tests/rustdoc-gui/search-result-impl-disambiguation.goml43
-rw-r--r--tests/rustdoc-gui/sidebar-mobile.goml4
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml4
-rw-r--r--tests/rustdoc-gui/sidebar.goml37
-rw-r--r--tests/rustdoc-gui/source-anchor-scroll.goml8
-rw-r--r--tests/rustdoc-gui/source-code-page.goml21
-rw-r--r--tests/rustdoc-gui/src/staged_api/lib.rs2
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs18
-rw-r--r--tests/rustdoc-js-std/simd-type-signatures.js70
-rw-r--r--tests/rustdoc-js/auxiliary/equivalent.rs15
-rw-r--r--tests/rustdoc-js/search-method-disambiguate.js28
-rw-r--r--tests/rustdoc-js/search-method-disambiguate.rs22
-rw-r--r--tests/rustdoc-js/search-non-local-trait-impl.js9
-rw-r--r--tests/rustdoc-js/search-non-local-trait-impl.rs8
-rw-r--r--tests/rustdoc/auxiliary/enum-variant.rs48
-rw-r--r--tests/rustdoc/blanket-reexport-item.rs2
-rw-r--r--tests/rustdoc/const-effect-param.rs12
-rw-r--r--tests/rustdoc/const-fn-effects.rs19
-rw-r--r--tests/rustdoc/const-generics/const-impl.rs2
-rw-r--r--tests/rustdoc/crate-version-escape.rs2
-rw-r--r--tests/rustdoc/crate-version-extra.rs7
-rw-r--r--tests/rustdoc/crate-version.rs2
-rw-r--r--tests/rustdoc/enum-variant-value.rs191
-rw-r--r--tests/rustdoc/generic-impl.rs4
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/const-fn.rs5
-rw-r--r--tests/rustdoc/inline_cross/const-fn.rs10
-rw-r--r--tests/rustdoc/issue-32077-type-alias-impls.rs2
-rw-r--r--tests/rustdoc/issue-78701.rs2
-rw-r--r--tests/rustdoc/logo-class-default.rs6
-rw-r--r--tests/rustdoc/logo-class-rust.rs7
-rw-r--r--tests/rustdoc/logo-class.rs2
-rw-r--r--tests/rustdoc/primitive/primitive-generic-impl.rs2
-rw-r--r--tests/rustdoc/sidebar-links-to-foreign-impl.rs4
-rw-r--r--tests/rustdoc/src-links-auto-impls.rs4
-rw-r--r--tests/rustdoc/titles.rs3
-rw-r--r--tests/rustdoc/where-clause-order.rs13
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs6
-rw-r--r--tests/ui/associated-inherent-types/regionck-1.stderr11
-rw-r--r--tests/ui/associated-types/associated-types-coherence-failure.stderr8
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-2.stderr6
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-1.stderr8
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-2.stderr7
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.stderr34
-rw-r--r--tests/ui/async-await/in-trait/async-generics.stderr34
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-self-type.stderr7
-rw-r--r--tests/ui/coercion/issue-53475.stderr7
-rw-r--r--tests/ui/coherence/coherence-overlap-downstream.next.stderr2
-rw-r--r--tests/ui/coherence/coherence-overlap-downstream.old.stderr2
-rw-r--r--tests/ui/coherence/coherence-overlap-upstream.stderr2
-rw-r--r--tests/ui/coherence/coherence-wasm-bindgen.stderr14
-rw-r--r--tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr11
-rw-r--r--tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr11
-rw-r--r--tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr13
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-80742.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr14
-rw-r--r--tests/ui/consts/const-eval/unused-broken-const-late.rs20
-rw-r--r--tests/ui/consts/const-eval/unused-broken-const-late.stderr11
-rw-r--r--tests/ui/consts/const_in_pattern/issue-78057.rs1
-rw-r--r--tests/ui/consts/const_in_pattern/issue-78057.stderr17
-rw-r--r--tests/ui/consts/issue-102117.stderr14
-rw-r--r--tests/ui/consts/issue-67696-const-prop-ice.rs2
-rw-r--r--tests/ui/error-codes/E0030-teach.stderr2
-rw-r--r--tests/ui/error-codes/E0030.stderr2
-rw-r--r--tests/ui/error-codes/E0311.fixed2
-rw-r--r--tests/ui/error-codes/E0311.stderr20
-rw-r--r--tests/ui/error-codes/E0374.stderr5
-rw-r--r--tests/ui/error-codes/E0377.stderr2
-rw-r--r--tests/ui/error-codes/E0476.stderr4
-rw-r--r--tests/ui/feature-gates/doc-rust-logo.rs5
-rw-r--r--tests/ui/feature-gates/doc-rust-logo.stderr12
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr6
-rw-r--r--tests/ui/generic-associated-types/issue-84931.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-variances.rs14
-rw-r--r--tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr7
-rw-r--r--tests/ui/impl-trait/type_parameters_captured.stderr7
-rw-r--r--tests/ui/impl-trait/unactionable_diagnostic.fixed2
-rw-r--r--tests/ui/impl-trait/unactionable_diagnostic.rs2
-rw-r--r--tests/ui/impl-trait/unactionable_diagnostic.stderr5
-rw-r--r--tests/ui/invalid_dispatch_from_dyn_impls.stderr24
-rw-r--r--tests/ui/issues/issue-43355.stderr2
-rw-r--r--tests/ui/issues/issue-77919.stderr2
-rw-r--r--tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr49
-rw-r--r--tests/ui/lifetimes/lifetime-errors/issue_74400.stderr7
-rw-r--r--tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed2
-rw-r--r--tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr20
-rw-r--r--tests/ui/linkage-attr/link-self-contained-consistency.many.stderr2
-rw-r--r--tests/ui/linkage-attr/link-self-contained-consistency.one.stderr2
-rw-r--r--tests/ui/linkage-attr/link-self-contained-consistency.rs10
-rw-r--r--tests/ui/linkage-attr/unstable-flavor.bpf.stderr2
-rw-r--r--tests/ui/linkage-attr/unstable-flavor.ptx.stderr2
-rw-r--r--tests/ui/linkage-attr/unstable-flavor.rs8
-rw-r--r--tests/ui/lint/lint-type-overflow.stderr42
-rw-r--r--tests/ui/lint/unaligned_references.rs23
-rw-r--r--tests/ui/lint/unaligned_references.stderr52
-rw-r--r--tests/ui/macros/assert-long-condition.rs9
-rw-r--r--tests/ui/macros/assert-long-condition.run.stderr4
-rw-r--r--tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr7
-rw-r--r--tests/ui/match/match-range-fail-2.stderr6
-rw-r--r--tests/ui/match/validate-range-endpoints.rs59
-rw-r--r--tests/ui/match/validate-range-endpoints.stderr84
-rw-r--r--tests/ui/never_type/never-from-impl-is-reserved.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr5
-rw-r--r--tests/ui/nll/issue-98589-closures-relate-named-regions.stderr8
-rw-r--r--tests/ui/nll/issue-98693.stderr7
-rw-r--r--tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr10
-rw-r--r--tests/ui/nll/ty-outlives/impl-trait-outlives.stderr10
-rw-r--r--tests/ui/nll/ty-outlives/projection-implied-bounds.stderr7
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr22
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr22
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-closure.stderr10
-rw-r--r--tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr12
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr6
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr6
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-none.stderr5
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr4
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr10
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr10
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-fn-body.stderr4
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-fn.stderr10
-rw-r--r--tests/ui/nll/user-annotations/normalization-infer.stderr49
-rw-r--r--tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr8
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-2.rs (renamed from tests/ui/parser/attr-bad-meta-2.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-2.stderr (renamed from tests/ui/parser/attr-bad-meta-2.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-3.rs (renamed from tests/ui/parser/attr-bad-meta-3.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-3.stderr (renamed from tests/ui/parser/attr-bad-meta-3.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta.rs (renamed from tests/ui/parser/attr-bad-meta.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta.stderr (renamed from tests/ui/parser/attr-bad-meta.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-before-eof.rs (renamed from tests/ui/parser/attr-before-eof.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-before-eof.stderr (renamed from tests/ui/parser/attr-before-eof.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-dangling-in-fn.rs (renamed from tests/ui/parser/attr-dangling-in-fn.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-dangling-in-fn.stderr (renamed from tests/ui/parser/attr-dangling-in-fn.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-dangling-in-mod.rs (renamed from tests/ui/parser/attr-dangling-in-mod.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-dangling-in-mod.stderr (renamed from tests/ui/parser/attr-dangling-in-mod.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs (renamed from tests/ui/parser/attr-stmt-expr-attr-bad.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr (renamed from tests/ui/parser/attr-stmt-expr-attr-bad.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr-with-a-semicolon.rs (renamed from tests/ui/parser/attr-with-a-semicolon.rs)0
-rw-r--r--tests/ui/parser/attribute/attr-with-a-semicolon.stderr (renamed from tests/ui/parser/attr-with-a-semicolon.stderr)0
-rw-r--r--tests/ui/parser/attribute/attr.rs (renamed from tests/ui/parser/attr.rs)0
-rw-r--r--tests/ui/parser/attribute/attr.stderr (renamed from tests/ui/parser/attr.stderr)0
-rw-r--r--tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.rs (renamed from tests/ui/parser/attribute-with-no-generics-in-parameter-list.rs)0
-rw-r--r--tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.stderr (renamed from tests/ui/parser/attribute-with-no-generics-in-parameter-list.stderr)0
-rw-r--r--tests/ui/parser/attribute/attrs-after-extern-mod.rs (renamed from tests/ui/parser/attrs-after-extern-mod.rs)0
-rw-r--r--tests/ui/parser/attribute/attrs-after-extern-mod.stderr (renamed from tests/ui/parser/attrs-after-extern-mod.stderr)0
-rw-r--r--tests/ui/parser/break-in-unlabeled-block-in-macro.rs43
-rw-r--r--tests/ui/parser/break-in-unlabeled-block-in-macro.stderr69
-rw-r--r--tests/ui/parser/break-in-unlabeled-block.fixed11
-rw-r--r--tests/ui/parser/break-in-unlabeled-block.rs11
-rw-r--r--tests/ui/parser/break-in-unlabeled-block.stderr27
-rw-r--r--tests/ui/pattern/non-structural-match-types.rs4
-rw-r--r--tests/ui/pattern/non-structural-match-types.stderr4
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.rs29
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.stderr137
-rw-r--r--tests/ui/privacy/private-in-public-warn.stderr2
-rw-r--r--tests/ui/privacy/private-in-public.stderr2
-rw-r--r--tests/ui/privacy/where-priv-type.stderr7
-rw-r--r--tests/ui/privacy/where-pub-type-impls-priv-trait.stderr7
-rw-r--r--tests/ui/proc-macro/issue-75930-derive-cfg.rs30
-rw-r--r--tests/ui/proc-macro/issue-75930-derive-cfg.stderr4
-rw-r--r--tests/ui/proc-macro/issue-75930-derive-cfg.stdout768
-rw-r--r--tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr4
-rw-r--r--tests/ui/regions/closure-in-projection-issue-97405.stderr12
-rw-r--r--tests/ui/regions/regions-close-associated-type-into-object.stderr40
-rw-r--r--tests/ui/regions/regions-close-object-into-object-4.stderr28
-rw-r--r--tests/ui/regions/regions-close-object-into-object-5.stderr28
-rw-r--r--tests/ui/regions/regions-close-over-type-parameter-1.stderr11
-rw-r--r--tests/ui/regions/regions-close-param-into-object.stderr24
-rw-r--r--tests/ui/regions/regions-implied-bounds-projection-gap-1.stderr5
-rw-r--r--tests/ui/regions/regions-infer-bound-from-trait-self.stderr11
-rw-r--r--tests/ui/regions/regions-infer-bound-from-trait.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr7
-rw-r--r--tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr13
-rw-r--r--tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr8
-rw-r--r--tests/ui/specialization/issue-52050.stderr10
-rw-r--r--tests/ui/suggestions/issue-102972.fixed41
-rw-r--r--tests/ui/suggestions/issue-102972.rs25
-rw-r--r--tests/ui/suggestions/issue-102972.stderr56
-rw-r--r--tests/ui/suggestions/lifetimes/issue-105544.fixed14
-rw-r--r--tests/ui/suggestions/lifetimes/issue-105544.rs6
-rw-r--r--tests/ui/suggestions/lifetimes/issue-105544.stderr104
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed7
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs7
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr23
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr99
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed47
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-bound-scope.rs47
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr71
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-missing-lifetime.fixed52
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-missing-lifetime.rs52
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-missing-lifetime.stderr66
-rw-r--r--tests/ui/suggestions/suggest-impl-trait-lifetime.fixed3
-rw-r--r--tests/ui/suggestions/suggest-impl-trait-lifetime.rs3
-rw-r--r--tests/ui/suggestions/suggest-impl-trait-lifetime.stderr7
-rw-r--r--tests/ui/trait-bounds/impl-bound-with-references-error.stderr7
-rw-r--r--tests/ui/traits/issue-33140-hack-boundaries.stderr2
-rw-r--r--tests/ui/traits/new-solver/coherence/issue-102048.stderr12
-rw-r--r--tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs12
-rw-r--r--tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr2
-rw-r--r--tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs11
-rw-r--r--tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr20
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs9
-rw-r--r--tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/wf-nested.fail.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr7
-rw-r--r--tests/ui/typeck/escaping_bound_vars.rs16
-rw-r--r--tests/ui/typeck/escaping_bound_vars.stderr10
-rw-r--r--tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs96
-rw-r--r--tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr255
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs32
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr123
-rw-r--r--tests/ui/wf/wf-impl-associated-type-region.stderr4
-rw-r--r--tests/ui/wf/wf-in-fn-type-static.stderr14
-rw-r--r--tests/ui/wf/wf-in-obj-type-static.stderr7
-rw-r--r--tests/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr8
-rw-r--r--tests/ui/wf/wf-trait-associated-type-region.stderr11
622 files changed, 13101 insertions, 5918 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4e599829097..8c207e7ea11 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,7 +22,6 @@ name: CI
       - try
       - try-perf
       - automation/bors/try
-      - automation/bors/try-merge
       - master
   pull_request:
     branches:
diff --git a/Cargo.lock b/Cargo.lock
index 3ad9d61e487..48d13e17d62 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2684,6 +2684,7 @@ dependencies = [
  "serde",
  "serde_json",
  "sysinfo",
+ "tabled",
  "tar",
  "tempfile",
  "xz",
@@ -2751,6 +2752,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "papergrid"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8"
+dependencies = [
+ "bytecount",
+ "fnv",
+ "unicode-width",
+]
+
+[[package]]
 name = "parking_lot"
 version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2959,6 +2971,30 @@ dependencies = [
 ]
 
 [[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
 name = "proc-macro-hack"
 version = "0.5.20+deprecated"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4443,7 +4479,6 @@ dependencies = [
 name = "rustc_session"
 version = "0.0.0"
 dependencies = [
- "bitflags 1.3.2",
  "getopts",
  "libc",
  "rustc_ast",
@@ -4468,6 +4503,7 @@ dependencies = [
 name = "rustc_smir"
 version = "0.0.0"
 dependencies = [
+ "rustc_data_structures",
  "rustc_driver",
  "rustc_hir",
  "rustc_interface",
@@ -5210,6 +5246,30 @@ dependencies = [
 ]
 
 [[package]]
+name = "tabled"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d38d39c754ae037a9bc3ca1580a985db7371cd14f1229172d1db9093feb6739"
+dependencies = [
+ "papergrid",
+ "tabled_derive",
+ "unicode-width",
+]
+
+[[package]]
+name = "tabled_derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
 name = "tar"
 version = "0.4.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/RELEASES.md b/RELEASES.md
index e261294a032..1cc110e6607 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -229,6 +229,7 @@ Compatibility Notes
   this should only impact users of other registries, or people who don't publish
   to a registry.
   [#12291](https://github.com/rust-lang/cargo/pull/12291)
+- [Demoted `mips*-unknown-linux-gnu*` targets from host tier 2 to target tier 3 support.](https://github.com/rust-lang/rust/pull/113274)
 
 Version 1.71.1 (2023-08-03)
 ===========================
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index bf8a7eb293e..54274f15356 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -11,6 +11,8 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(no_crate_inject, attr(deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(new_uninit)]
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index db008ea139d..7b7078fabbb 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -197,10 +197,10 @@ impl Attribute {
                 .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
                 .to_attr_token_stream()
                 .to_tokenstream(),
-            &AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
-                Token::new(token::DocComment(comment_kind, self.style, data), self.span),
-                Spacing::Alone,
-            )]),
+            &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone(
+                token::DocComment(comment_kind, self.style, data),
+                self.span,
+            ),
         }
     }
 }
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index b07ed1d1c74..ddc7c8ee825 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -8,6 +8,9 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(const_trait_impl)]
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 09bfbd02198..2de398521f5 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -404,7 +404,7 @@ impl Token {
         [DotDot, DotDotDot, DotDotEq].contains(&self.kind)
     }
 
-    pub fn is_op(&self) -> bool {
+    pub fn is_punct(&self) -> bool {
         match self.kind {
             Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
             | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index edc1e2f0b84..5bfc956aba1 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1623,12 +1623,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
                 bounded_ty: self
                     .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
-                bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
-                    self.lower_param_bound(
-                        bound,
-                        &ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                    )
-                })),
+                bounds: self.lower_param_bounds(
+                    bounds,
+                    &ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                ),
                 span: self.lower_span(*span),
                 origin: PredicateOrigin::WhereClause,
             }),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 8b7e91882fc..e71f421659e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -148,7 +148,7 @@ pub fn print_crate<'a>(
 
 /// This makes printed token streams look slightly nicer,
 /// and also addresses some specific regressions described in #63896 and #73345.
-fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
+fn space_between(prev: &TokenTree, curr: &TokenTree) -> bool {
     if let TokenTree::Token(token, _) = prev {
         // No space after these tokens, e.g. `x.y`, `$e`
         // (The carets point to `prev`.)       ^     ^
@@ -159,9 +159,9 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
             return comment_kind != CommentKind::Line;
         }
     }
-    match tt {
+    match curr {
         // No space before these tokens, e.g. `foo,`, `println!`, `x.y`
-        // (The carets point to `token`.)         ^           ^     ^
+        // (The carets point to `curr`.)          ^           ^     ^
         //
         // FIXME: having `Not` here works well for macro invocations like
         // `println!()`, but is bad when `!` means "logical not" or "the never
@@ -575,7 +575,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         while let Some(tt) = iter.next() {
             self.print_tt(tt, convert_dollar_crate);
             if let Some(next) = iter.peek() {
-                if tt_prepend_space(next, tt) {
+                if space_between(tt, next) {
                     self.space();
                 }
             }
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 4ac633c263f..6ea84620bbe 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,6 +1,7 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::graph::WithSuccessors;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{
     self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
@@ -222,6 +223,7 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
     }
 }
 
+// This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
 pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
@@ -238,15 +240,196 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
     prec.borrows_out_of_scope_at_location
 }
 
+struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
+    visited: BitSet<mir::BasicBlock>,
+    visit_stack: Vec<mir::BasicBlock>,
+    body: &'a Body<'tcx>,
+    regioncx: &'a RegionInferenceContext<'tcx>,
+
+    loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
+}
+
+impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
+    fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
+        Self {
+            visited: BitSet::new_empty(body.basic_blocks.len()),
+            visit_stack: vec![],
+            body,
+            regioncx,
+            loans_out_of_scope_at_location: FxIndexMap::default(),
+        }
+    }
+}
+
+impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
+    /// Loans are in scope while they are live: whether they are contained within any live region.
+    /// In the location-insensitive analysis, a loan will be contained in a region if the issuing
+    /// region can reach it in the subset graph. So this is a reachability problem.
+    fn precompute_loans_out_of_scope(
+        &mut self,
+        loan_idx: BorrowIndex,
+        issuing_region: RegionVid,
+        loan_issued_at: Location,
+    ) {
+        let sccs = self.regioncx.constraint_sccs();
+        let issuing_region_scc = sccs.scc(issuing_region);
+
+        // We first handle the cases where the loan doesn't go out of scope, depending on the issuing
+        // region's successors.
+        for scc in sccs.depth_first_search(issuing_region_scc) {
+            // 1. Via member constraints
+            //
+            // The issuing region can flow into the choice regions, and they are either:
+            // - placeholders or free regions themselves,
+            // - or also transitively outlive a free region.
+            //
+            // That is to say, if there are member constraints here, the loan escapes the function
+            // and cannot go out of scope. We can early return.
+            if self.regioncx.scc_has_member_constraints(scc) {
+                return;
+            }
+
+            // 2. Via regions that are live at all points: placeholders and free regions.
+            //
+            // If the issuing region outlives such a region, its loan escapes the function and
+            // cannot go out of scope. We can early return.
+            if self.regioncx.scc_is_live_at_all_points(scc) {
+                return;
+            }
+        }
+
+        let first_block = loan_issued_at.block;
+        let first_bb_data = &self.body.basic_blocks[first_block];
+
+        // The first block we visit is the one where the loan is issued, starting from the statement
+        // where the loan is issued: at `loan_issued_at`.
+        let first_lo = loan_issued_at.statement_index;
+        let first_hi = first_bb_data.statements.len();
+
+        if let Some(kill_location) =
+            self.loan_kill_location(loan_idx, loan_issued_at, first_block, first_lo, first_hi)
+        {
+            debug!("loan {:?} gets killed at {:?}", loan_idx, kill_location);
+            self.loans_out_of_scope_at_location.entry(kill_location).or_default().push(loan_idx);
+
+            // The loan dies within the first block, we're done and can early return.
+            return;
+        }
+
+        // The loan is not dead. Add successor BBs to the work list, if necessary.
+        for succ_bb in first_bb_data.terminator().successors() {
+            if self.visited.insert(succ_bb) {
+                self.visit_stack.push(succ_bb);
+            }
+        }
+
+        // We may end up visiting `first_block` again. This is not an issue: we know at this point
+        // that the loan is not killed in the `first_lo..=first_hi` range, so checking the
+        // `0..first_lo` range and the `0..first_hi` range gives the same result.
+        while let Some(block) = self.visit_stack.pop() {
+            let bb_data = &self.body[block];
+            let num_stmts = bb_data.statements.len();
+            if let Some(kill_location) =
+                self.loan_kill_location(loan_idx, loan_issued_at, block, 0, num_stmts)
+            {
+                debug!("loan {:?} gets killed at {:?}", loan_idx, kill_location);
+                self.loans_out_of_scope_at_location
+                    .entry(kill_location)
+                    .or_default()
+                    .push(loan_idx);
+
+                // The loan dies within this block, so we don't need to visit its successors.
+                continue;
+            }
+
+            // Add successor BBs to the work list, if necessary.
+            for succ_bb in bb_data.terminator().successors() {
+                if self.visited.insert(succ_bb) {
+                    self.visit_stack.push(succ_bb);
+                }
+            }
+        }
+
+        self.visited.clear();
+        assert!(self.visit_stack.is_empty(), "visit stack should be empty");
+    }
+
+    /// Returns the lowest statement in `start..=end`, where the loan goes out of scope, if any.
+    /// This is the statement where the issuing region can't reach any of the regions that are live
+    /// at this point.
+    fn loan_kill_location(
+        &self,
+        loan_idx: BorrowIndex,
+        loan_issued_at: Location,
+        block: BasicBlock,
+        start: usize,
+        end: usize,
+    ) -> Option<Location> {
+        for statement_index in start..=end {
+            let location = Location { block, statement_index };
+
+            // Check whether the issuing region can reach local regions that are live at this point:
+            // - a loan is always live at its issuing location because it can reach the issuing
+            // region, which is always live at this location.
+            if location == loan_issued_at {
+                continue;
+            }
+
+            // - the loan goes out of scope at `location` if it's not contained within any regions
+            // live at this point.
+            //
+            // FIXME: if the issuing region `i` can reach a live region `r` at point `p`, and `r` is
+            // live at point `q`, then it's guaranteed that `i` would reach `r` at point `q`.
+            // Reachability is location-insensitive, and we could take advantage of that, by jumping
+            // to a further point than just the next statement: we can jump to the furthest point
+            // within the block where `r` is live.
+            if self.regioncx.is_loan_live_at(loan_idx, location) {
+                continue;
+            }
+
+            // No live region is reachable from the issuing region: the loan is killed at this
+            // point.
+            return Some(location);
+        }
+
+        None
+    }
+}
+
 impl<'a, 'tcx> Borrows<'a, 'tcx> {
     pub fn new(
         tcx: TyCtxt<'tcx>,
         body: &'a Body<'tcx>,
-        nonlexical_regioncx: &'a RegionInferenceContext<'tcx>,
+        regioncx: &'a RegionInferenceContext<'tcx>,
         borrow_set: &'a BorrowSet<'tcx>,
     ) -> Self {
-        let borrows_out_of_scope_at_location =
-            calculate_borrows_out_of_scope_at_location(body, nonlexical_regioncx, borrow_set);
+        let mut borrows_out_of_scope_at_location =
+            calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set);
+
+        // The in-tree polonius analysis computes loans going out of scope using the set-of-loans
+        // model, and makes sure they're identical to the existing computation of the set-of-points
+        // model.
+        if tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
+            let mut polonius_prec = PoloniusOutOfScopePrecomputer::new(body, regioncx);
+            for (loan_idx, loan_data) in borrow_set.iter_enumerated() {
+                let issuing_region = loan_data.region;
+                let issued_location = loan_data.reserve_location;
+
+                polonius_prec.precompute_loans_out_of_scope(
+                    loan_idx,
+                    issuing_region,
+                    issued_location,
+                );
+            }
+
+            assert_eq!(
+                borrows_out_of_scope_at_location, polonius_prec.loans_out_of_scope_at_location,
+                "the loans out of scope must be the same as the borrows out of scope"
+            );
+
+            borrows_out_of_scope_at_location = polonius_prec.loans_out_of_scope_at_location;
+        }
+
         Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location }
     }
 
@@ -333,6 +516,13 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
     }
 }
 
+/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
+/// - we gen the introduced loans
+/// - we kill loans on locals going out of (regular) scope
+/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a
+///   region stops containing the CFG points reachable from the issuing location.
+/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
+///   `a.b.c` when `a` is overwritten.
 impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     type Idx = BorrowIndex;
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 4488276e0e7..ec9bb215f3f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1329,42 +1329,168 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             issue_span: Span,
             expr_span: Span,
             body_expr: Option<&'hir hir::Expr<'hir>>,
-            loop_bind: Option<Symbol>,
+            loop_bind: Option<&'hir Ident>,
+            loop_span: Option<Span>,
+            head_span: Option<Span>,
+            pat_span: Option<Span>,
+            head: Option<&'hir hir::Expr<'hir>>,
         }
         impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
             fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
-                if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind &&
-                    let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind &&
-                    let hir::ExprKind::Call(path, _args) = call.kind &&
-                    let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind &&
-                    let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind &&
-                    let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path &&
-                    let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field &&
-                    self.issue_span.source_equal(call.span) {
-                        self.loop_bind = Some(ident.name);
+                // Try to find
+                // let result = match IntoIterator::into_iter(<head>) {
+                //     mut iter => {
+                //         [opt_ident]: loop {
+                //             match Iterator::next(&mut iter) {
+                //                 None => break,
+                //                 Some(<pat>) => <body>,
+                //             };
+                //         }
+                //     }
+                // };
+                // corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
+                if let hir::ExprKind::Call(path, [arg]) = ex.kind
+                    && let hir::ExprKind::Path(
+                        hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _),
+                    ) = path.kind
+                    && arg.span.contains(self.issue_span)
+                {
+                    // Find `IntoIterator::into_iter(<head>)`
+                    self.head = Some(arg);
+                }
+                if let hir::ExprKind::Loop(
+                    hir::Block { stmts: [stmt, ..], .. },
+                    _,
+                    hir::LoopSource::ForLoop,
+                    _,
+                ) = ex.kind
+                    && let hir::StmtKind::Expr(hir::Expr {
+                        kind: hir::ExprKind::Match(call, [_, bind, ..], _),
+                        span: head_span,
+                        ..
+                    }) = stmt.kind
+                    && let hir::ExprKind::Call(path, _args) = call.kind
+                    && let hir::ExprKind::Path(
+                        hir::QPath::LangItem(LangItem::IteratorNext, _, _),
+                    ) = path.kind
+                    && let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
+                    && let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path
+                    && call.span.contains(self.issue_span)
+                {
+                    // Find `<pat>` and the span for the whole `for` loop.
+                    if let PatField { pat: hir::Pat {
+                        kind: hir::PatKind::Binding(_, _, ident, ..),
+                        ..
+                    }, ..} = field {
+                        self.loop_bind = Some(ident);
                     }
+                    self.head_span = Some(*head_span);
+                    self.pat_span = Some(pat_span);
+                    self.loop_span = Some(stmt.span);
+                }
 
-                if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind &&
-                    body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) {
-                        self.body_expr = Some(ex);
+                if let hir::ExprKind::MethodCall(body_call, recv, ..) = ex.kind
+                    && body_call.ident.name == sym::next
+                    && recv.span.source_equal(self.expr_span)
+                {
+                    self.body_expr = Some(ex);
                 }
 
                 hir::intravisit::walk_expr(self, ex);
             }
         }
-        let mut finder =
-            ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None };
+        let mut finder = ExprFinder {
+            expr_span: span,
+            issue_span,
+            loop_bind: None,
+            body_expr: None,
+            head_span: None,
+            loop_span: None,
+            pat_span: None,
+            head: None,
+        };
         finder.visit_expr(hir.body(body_id).value);
 
-        if let Some(loop_bind) = finder.loop_bind &&
-            let Some(body_expr) = finder.body_expr &&
-                let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) &&
-                let Some(trait_did) = tcx.trait_of_item(def_id) &&
-                tcx.is_diagnostic_item(sym::Iterator, trait_did) {
-                    err.note(format!(
-                        "a for loop advances the iterator for you, the result is stored in `{loop_bind}`."
+        if let Some(body_expr) = finder.body_expr
+            && let Some(loop_span) = finder.loop_span
+            && let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id)
+            && let Some(trait_did) = tcx.trait_of_item(def_id)
+            && tcx.is_diagnostic_item(sym::Iterator, trait_did)
+        {
+            if let Some(loop_bind) = finder.loop_bind {
+                err.note(format!(
+                    "a for loop advances the iterator for you, the result is stored in `{}`",
+                    loop_bind.name,
+                ));
+            } else {
+                err.note(
+                    "a for loop advances the iterator for you, the result is stored in its pattern",
+                );
+            }
+            let msg = "if you want to call `next` on a iterator within the loop, consider using \
+                       `while let`";
+            if let Some(head) = finder.head
+                && let Some(pat_span) = finder.pat_span
+                && loop_span.contains(body_expr.span)
+                && loop_span.contains(head.span)
+            {
+                let sm = self.infcx.tcx.sess.source_map();
+
+                let mut sugg = vec![];
+                if let hir::ExprKind::Path(hir::QPath::Resolved(None, _)) = head.kind {
+                    // A bare path doesn't need a `let` assignment, it's already a simple
+                    // binding access.
+                    // As a new binding wasn't added, we don't need to modify the advancing call.
+                    sugg.push((
+                        loop_span.with_hi(pat_span.lo()),
+                        format!("while let Some("),
+                    ));
+                    sugg.push((
+                        pat_span.shrink_to_hi().with_hi(head.span.lo()),
+                        ") = ".to_string(),
+                    ));
+                    sugg.push((
+                        head.span.shrink_to_hi(),
+                        ".next()".to_string(),
+                    ));
+                } else {
+                    // Needs a new a `let` binding.
+                    let indent = if let Some(indent) = sm.indentation_before(loop_span) {
+                        format!("\n{indent}")
+                    } else {
+                        " ".to_string()
+                    };
+                    let Ok(head_str) = sm.span_to_snippet(head.span) else {
+                        err.help(msg);
+                        return;
+                    };
+                    sugg.push((
+                        loop_span.with_hi(pat_span.lo()),
+                        format!("let iter = {head_str};{indent}while let Some("),
                     ));
-                    err.help("if you want to call `next` on an iterator within the loop, consider using `while let`.");
+                    sugg.push((
+                        pat_span.shrink_to_hi().with_hi(head.span.hi()),
+                        ") = iter.next()".to_string(),
+                    ));
+                    // As a new binding was added, we should change how the iterator is advanced to
+                    // use the newly introduced binding.
+                    if let hir::ExprKind::MethodCall(_, recv, ..) = body_expr.kind
+                        && let hir::ExprKind::Path(hir::QPath::Resolved(None, ..)) = recv.kind
+                    {
+                        // As we introduced a `let iter = <head>;`, we need to change where the
+                        // already borrowed value was accessed from `<recv>.next()` to
+                        // `iter.next()`.
+                        sugg.push((recv.span, "iter".to_string()));
+                    }
+                }
+                err.multipart_suggestion(
+                    msg,
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                err.help(msg);
+            }
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 9916ebca32f..c54e7070478 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -41,7 +41,8 @@ pub(crate) trait AllFactsExt {
 impl AllFactsExt for AllFacts {
     /// Return
     fn enabled(tcx: TyCtxt<'_>) -> bool {
-        tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius
+        tcx.sess.opts.unstable_opts.nll_facts
+            || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled()
     }
 
     fn write_to_dir(
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 3f60f5aca71..0ea4401a878 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -169,10 +169,11 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
     upvars: &[Upvar<'tcx>],
     consumer_options: Option<ConsumerOptions>,
 ) -> NllOutput<'tcx> {
+    let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
     let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
-        || infcx.tcx.sess.opts.unstable_opts.polonius;
+        || is_polonius_legacy_enabled;
     let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
-        || infcx.tcx.sess.opts.unstable_opts.polonius;
+        || is_polonius_legacy_enabled;
     let mut all_facts =
         (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
 
@@ -181,22 +182,26 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
     let elements = &Rc::new(RegionValueElements::new(&body));
 
     // Run the MIR type-checker.
-    let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
-        type_check::type_check(
-            infcx,
-            param_env,
-            body,
-            promoted,
-            &universal_regions,
-            location_table,
-            borrow_set,
-            &mut all_facts,
-            flow_inits,
-            move_data,
-            elements,
-            upvars,
-            polonius_input,
-        );
+    let MirTypeckResults {
+        constraints,
+        universal_region_relations,
+        opaque_type_values,
+        live_loans,
+    } = type_check::type_check(
+        infcx,
+        param_env,
+        body,
+        promoted,
+        &universal_regions,
+        location_table,
+        borrow_set,
+        &mut all_facts,
+        flow_inits,
+        move_data,
+        elements,
+        upvars,
+        polonius_input,
+    );
 
     if let Some(all_facts) = &mut all_facts {
         let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
@@ -274,6 +279,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
         type_tests,
         liveness_constraints,
         elements,
+        live_loans,
     );
 
     // Generate various additional constraints.
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 852935676b6..96cbe98c216 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -7,6 +7,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_index::bit_set::SparseBitMatrix;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::outlives::test_type_match;
 use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
@@ -21,6 +22,7 @@ use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::Span;
 
+use crate::dataflow::BorrowIndex;
 use crate::{
     constraints::{
         graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
@@ -30,8 +32,8 @@ use crate::{
     nll::PoloniusOutput,
     region_infer::reverse_sccs::ReverseSccGraph,
     region_infer::values::{
-        LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
-        ToElementIndex,
+        LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements,
+        RegionValues, ToElementIndex,
     },
     type_check::{free_region_relations::UniversalRegionRelations, Locations},
     universal_regions::UniversalRegions,
@@ -119,6 +121,9 @@ pub struct RegionInferenceContext<'tcx> {
     /// Information about how the universally quantified regions in
     /// scope on this function relate to one another.
     universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
+
+    /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
+    live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
 }
 
 /// Each time that `apply_member_constraint` is successful, it appends
@@ -330,6 +335,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         type_tests: Vec<TypeTest<'tcx>>,
         liveness_constraints: LivenessValues<RegionVid>,
         elements: &Rc<RegionValueElements>,
+        live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
     ) -> Self {
         debug!("universal_regions: {:#?}", universal_regions);
         debug!("outlives constraints: {:#?}", outlives_constraints);
@@ -383,6 +389,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             type_tests,
             universal_regions,
             universal_region_relations,
+            live_loans,
         };
 
         result.init_free_and_bound_regions();
@@ -683,7 +690,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // In Polonius mode, the errors about missing universal region relations are in the output
         // and need to be emitted or propagated. Otherwise, we need to check whether the
         // constraints were too strong, and if so, emit or propagate those errors.
-        if infcx.tcx.sess.opts.unstable_opts.polonius {
+        if infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() {
             self.check_polonius_subset_errors(
                 outlives_requirements.as_mut(),
                 &mut errors_buffer,
@@ -2279,6 +2286,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
         None
     }
+
+    /// Access to the SCC constraint graph.
+    pub(crate) fn constraint_sccs(&self) -> &Sccs<RegionVid, ConstraintSccIndex> {
+        self.constraint_sccs.as_ref()
+    }
+
+    /// Returns whether the given SCC has any member constraints.
+    pub(crate) fn scc_has_member_constraints(&self, scc: ConstraintSccIndex) -> bool {
+        self.member_constraints.indices(scc).next().is_some()
+    }
+
+    /// Returns whether the given SCC is live at all points: whether the representative is a
+    /// placeholder or a free region.
+    pub(crate) fn scc_is_live_at_all_points(&self, scc: ConstraintSccIndex) -> bool {
+        // FIXME: there must be a cleaner way to find this information. At least, when
+        // higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
+        // need to check whether this is a universal region.
+        let representative = self.scc_representatives[scc];
+        let origin = self.var_infos[representative].origin;
+        let live_at_all_points = matches!(
+            origin,
+            RegionVariableOrigin::Nll(
+                NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
+            )
+        );
+        live_at_all_points
+    }
+
+    /// Returns whether the `loan_idx` is live at the given `location`: whether its issuing
+    /// region is contained within the type of a variable that is live at this point.
+    /// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
+    pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
+        let point = self.liveness_constraints.point_from_location(location);
+        self.live_loans.contains(point, loan_idx)
+    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index d205862cd3f..38452df32e9 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -176,6 +176,11 @@ impl<N: Idx> LivenessValues<N> {
     pub(crate) fn region_value_str(&self, r: N) -> String {
         region_value_str(self.get_elements(r).map(RegionElement::Location))
     }
+
+    #[inline]
+    pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
+        self.elements.point_from_location(location)
+    }
 }
 
 /// Maps from `ty::PlaceholderRegion` values that are used in the rest of
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 5702d39db32..21da05c32dd 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,10 +1,11 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_index::bit_set::HybridBitSet;
+use rustc_data_structures::graph::WithSuccessors;
+use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 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_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
 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};
@@ -14,6 +15,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
 use rustc_mir_dataflow::ResultsCursor;
 
+use crate::dataflow::BorrowIndex;
 use crate::{
     region_infer::values::{self, PointIndex, RegionValueElements},
     type_check::liveness::local_use_map::LocalUseMap,
@@ -50,6 +52,33 @@ pub(super) fn trace<'mir, 'tcx>(
 
     let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
 
+    // When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
+    let num_loans = typeck.borrowck_context.borrow_set.len();
+    let mut inflowing_loans = SparseBitMatrix::new(num_loans);
+    if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
+        let borrowck_context = &typeck.borrowck_context;
+        let borrow_set = &borrowck_context.borrow_set;
+        let constraint_set = &borrowck_context.constraints.outlives_constraints;
+
+        let num_region_vars = typeck.infcx.num_region_vars();
+        let graph = constraint_set.graph(num_region_vars);
+        let region_graph =
+            graph.region_graph(&constraint_set, borrowck_context.universal_regions.fr_static);
+
+        // Traverse each issuing region's constraints, and record the loan as flowing into the
+        // outlived region.
+        for (loan, issuing_region_data) in borrow_set.iter_enumerated() {
+            for succ in region_graph.depth_first_search(issuing_region_data.region) {
+                // We don't need to mention that a loan flows into its issuing region.
+                if succ == issuing_region_data.region {
+                    continue;
+                }
+
+                inflowing_loans.insert(succ, loan);
+            }
+        }
+    };
+
     let cx = LivenessContext {
         typeck,
         body,
@@ -58,6 +87,7 @@ pub(super) fn trace<'mir, 'tcx>(
         local_use_map,
         move_data,
         drop_data: FxIndexMap::default(),
+        inflowing_loans,
     };
 
     let mut results = LivenessResults::new(cx);
@@ -95,6 +125,9 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
     /// Index indicating where each variable is assigned, used, or
     /// dropped.
     local_use_map: &'me LocalUseMap,
+
+    /// Set of loans that flow into a given region, when using `-Zpolonius=next`.
+    inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
 }
 
 struct DropData<'tcx> {
@@ -486,7 +519,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     ) {
         debug!("add_use_live_facts_for(value={:?})", value);
 
-        Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at)
+        Self::make_all_regions_live(
+            self.elements,
+            &mut self.typeck,
+            value,
+            live_at,
+            &self.inflowing_loans,
+        );
     }
 
     /// Some variable with type `live_ty` is "drop live" at `location`
@@ -537,7 +576,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         // All things in the `outlives` array may be touched by
         // the destructor and must be live at this point.
         for &kind in &drop_data.dropck_result.kinds {
-            Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at);
+            Self::make_all_regions_live(
+                self.elements,
+                &mut self.typeck,
+                kind,
+                live_at,
+                &self.inflowing_loans,
+            );
 
             polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind);
         }
@@ -548,6 +593,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         typeck: &mut TypeChecker<'_, 'tcx>,
         value: impl TypeVisitable<TyCtxt<'tcx>>,
         live_at: &IntervalSet<PointIndex>,
+        inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>,
     ) {
         debug!("make_all_regions_live(value={:?})", value);
         debug!(
@@ -556,15 +602,35 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         );
 
         let tcx = typeck.tcx();
+        let borrowck_context = &mut typeck.borrowck_context;
+
+        // When using `-Zpolonius=next`, we want to record the loans that flow into this value's
+        // regions as being live at the given `live_at` points: this will be used to compute the
+        // location where a loan goes out of scope.
+        let num_loans = borrowck_context.borrow_set.len();
+        let mut value_loans = HybridBitSet::new_empty(num_loans);
+
         tcx.for_each_free_region(&value, |live_region| {
-            let live_region_vid =
-                typeck.borrowck_context.universal_regions.to_region_vid(live_region);
-            typeck
-                .borrowck_context
+            let live_region_vid = borrowck_context.universal_regions.to_region_vid(live_region);
+
+            borrowck_context
                 .constraints
                 .liveness_constraints
                 .add_elements(live_region_vid, live_at);
+
+            // There can only be inflowing loans for this region when we are using
+            // `-Zpolonius=next`.
+            if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
+                value_loans.union(inflowing);
+            }
         });
+
+        // Record the loans reaching the value.
+        if !value_loans.is_empty() {
+            for point in live_at.iter() {
+                borrowck_context.live_loans.union_row(point, &value_loans);
+            }
+        }
     }
 
     fn compute_drop_data(
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index e7b1a489f5d..1ec0e62d16a 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -14,6 +14,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_index::bit_set::SparseBitMatrix;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -50,6 +51,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
+use crate::dataflow::BorrowIndex;
+use crate::region_infer::values::PointIndex;
 use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
 use crate::{
     borrow_set::BorrowSet,
@@ -163,6 +166,9 @@ pub(crate) fn type_check<'mir, 'tcx>(
 
     debug!(?normalized_inputs_and_output);
 
+    // When using `-Zpolonius=next`, liveness will record the set of live loans per point.
+    let mut live_loans = SparseBitMatrix::new(borrow_set.len());
+
     let mut borrowck_context = BorrowCheckContext {
         universal_regions,
         location_table,
@@ -170,6 +176,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         all_facts,
         constraints: &mut constraints,
         upvars,
+        live_loans: &mut live_loans,
     };
 
     let mut checker = TypeChecker::new(
@@ -240,7 +247,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         })
         .collect();
 
-    MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
+    MirTypeckResults { constraints, universal_region_relations, opaque_type_values, live_loans }
 }
 
 fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
@@ -855,12 +862,21 @@ struct BorrowCheckContext<'a, 'tcx> {
     borrow_set: &'a BorrowSet<'tcx>,
     pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     upvars: &'a [Upvar<'tcx>],
+
+    /// The set of loans that are live at a given point in the CFG, filled in by `liveness::trace`,
+    /// when using `-Zpolonius=next`.
+    pub(crate) live_loans: &'a mut SparseBitMatrix<PointIndex, BorrowIndex>,
 }
 
+/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
+/// inference computation.
 pub(crate) struct MirTypeckResults<'tcx> {
     pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
     pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
     pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
+
+    /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
+    pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
 }
 
 /// A collection of region constraints that must be satisfied for the
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 9302db104b6..7abfcc8c50c 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -85,7 +85,7 @@ pub fn expand_assert<'cx>(
                 DUMMY_SP,
                 Symbol::intern(&format!(
                     "assertion failed: {}",
-                    pprust::expr_to_string(&cond_expr).escape_debug()
+                    pprust::expr_to_string(&cond_expr)
                 )),
             )],
         );
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index af8e43da4ea..7c324421be9 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -15,9 +15,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.66"
+version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
 
 [[package]]
 name = "arbitrary"
@@ -26,12 +26,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
 
 [[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
 name = "bitflags"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -39,9 +33,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bumpalo"
-version = "3.11.1"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "cfg-if"
@@ -51,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec27af72e56235eb326b5bf2de4e70ab7c5ac1fb683a1829595badaf821607fd"
+checksum = "03b9d1a9e776c27ad55d7792a380785d1fe8c2d7b099eed8dbd8f4af2b598192"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2231e12925e6c5f4bc9c95b62a798eea6ed669a95bc3e00f8b2adb3b7b9b7a80"
+checksum = "5528483314c2dd5da438576cd8a9d0b3cedad66fb8a4727f90cd319a81950038"
 dependencies = [
  "bumpalo",
  "cranelift-bforest",
@@ -72,7 +66,7 @@ dependencies = [
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
- "hashbrown 0.13.2",
+ "hashbrown 0.14.0",
  "log",
  "regalloc2",
  "smallvec",
@@ -81,39 +75,39 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "413b00b8dfb3aab85674a534677e7ca08854b503f164a70ec0634fce80996e2c"
+checksum = "0f46a8318163f7682e35b8730ba93c1b586a2da8ce12a0ed545efc1218550f70"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd0feb9ecc8193ef5cb04f494c5bd835e5bfec4bde726e7ac0444fc9dd76229e"
+checksum = "37d1239cfd50eecfaed468d46943f8650e32969591868ad50111613704da6c70"
 
 [[package]]
 name = "cranelift-control"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72eedd2afcf5fee1e042eaaf18d3750e48ad0eca364a9f5971ecfdd5ef85bf71"
+checksum = "bcc530560c8f16cc1d4dd7ea000c56f519c60d1a914977abe849ce555c35a61d"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7af19157be42671073cf8c2a52d6a4ae1e7b11f1dcb4131fede356d9f91c29dd"
+checksum = "f333fa641a9ad2bff0b107767dcb972c18c2bfab7969805a1d7e42449ccb0408"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2dc7636c5fad156be7d9ae691cd1aaecd97326caf2ab534ba168056d56aa76c"
+checksum = "06abf6563015a80f03f8bc4df307d0a81363f4eb73108df3a34f6e66fb6d5307"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -123,15 +117,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1111aea4fb6fade5779903f184249a3fc685a799fe4ec59126f9af59c7c2a74"
+checksum = "0eb29d0edc8a5c029ed0f7ca77501f272738e3c410020b4a00f42ffe8ad2a8aa"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dadf88076317f6286ec77ebbe65978734fb43b6befdc96f52ff4c4c511841644"
+checksum = "d16e8c5e212b1e63658aada17553497e7a259acab61f044d1f185527efa609fb"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -149,9 +143,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6bae8a82dbf82241b1083e57e06870d2c2bdc9852727be99d58477513816953"
+checksum = "d3b5fd273e1a959e920c7a9d790b1646d31acc8782bb549bad5ab85dd2fc9aa7"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -160,9 +154,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ecfc01a634448468a698beac433d98040033046678a0eed3ca39a3a9f63ae86"
+checksum = "006056a7fa920870bad06bf8e1b3033d70cbb7ee625b035efa9d90882a931868"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -171,9 +165,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee14a7276999f0dcaae2de84043e2c2de50820fb89b3db56fab586a4ad26734"
+checksum = "9c8be1b0e7720f30fec31be0c0b0b23caef2a73fa751190c6a251c1362e8f8c9"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -195,35 +189,29 @@ dependencies = [
 
 [[package]]
 name = "equivalent"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "fallible-iterator"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
 name = "gimli"
-version = "0.27.2"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
 dependencies = [
  "fallible-iterator",
- "indexmap 1.9.3",
+ "indexmap",
  "stable_deref_trait",
 ]
 
 [[package]]
 name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
-[[package]]
-name = "hashbrown"
 version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
@@ -236,15 +224,8 @@ name = "hashbrown"
 version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
-
-[[package]]
-name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
- "autocfg",
- "hashbrown 0.12.3",
+ "ahash",
 ]
 
 [[package]]
@@ -259,9 +240,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.138"
+version = "0.2.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
 
 [[package]]
 name = "libloading"
@@ -275,12 +256,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.17"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "mach"
@@ -293,27 +271,27 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.5.0"
+version = "2.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
 
 [[package]]
 name = "object"
-version = "0.30.4"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
+checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
 dependencies = [
  "crc32fast",
- "hashbrown 0.13.2",
- "indexmap 1.9.3",
+ "hashbrown 0.14.0",
+ "indexmap",
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.16.0"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
 name = "regalloc2"
@@ -357,7 +335,7 @@ dependencies = [
  "cranelift-native",
  "cranelift-object",
  "gimli",
- "indexmap 2.0.0",
+ "indexmap",
  "libloading",
  "object",
  "smallvec",
@@ -366,15 +344,15 @@ dependencies = [
 
 [[package]]
 name = "slice-group-by"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
+checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
 
 [[package]]
 name = "smallvec"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
 
 [[package]]
 name = "stable_deref_trait"
@@ -396,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "11.0.0"
+version = "13.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e34eb67f0829a5614ec54716c8e0c9fe68fab7b9df3686c85f719c9d247f7169"
+checksum = "c6ff5f3707a5e3797deeeeac6ac26b2e1dd32dbc06693c0ab52e8ac4d18ec706"
 dependencies = [
  "cfg-if",
  "libc",
@@ -438,9 +416,9 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -453,42 +431,42 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 8ded81d7399..28a37b7995b 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,15 +8,15 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.98", features = ["unwind", "all-arch"] }
-cranelift-frontend = { version = "0.98" }
-cranelift-module = { version = "0.98" }
-cranelift-native = { version = "0.98" }
-cranelift-jit = { version = "0.98", optional = true }
-cranelift-object = { version = "0.98" }
+cranelift-codegen = { version = "0.100", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.100" }
+cranelift-module = { version = "0.100" }
+cranelift-native = { version = "0.100" }
+cranelift-jit = { version = "0.100", optional = true }
+cranelift-object = { version = "0.100" }
 target-lexicon = "0.12.0"
-gimli = { version = "0.27.2", default-features = false, features = ["write"]}
-object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.28", default-features = false, features = ["write"]}
+object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 indexmap = "2.0.0"
 libloading = { version = "0.7.3", optional = true }
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index 62eaef359af..6f2027be96d 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -60,18 +60,14 @@ You need to do this steps to successfully compile and use the cranelift backend
 2. Run `python x.py setup` and choose option for compiler (`b`).
 3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt`
    * (Optional) You can also build cargo by adding `src/tools/cargo` to previous command.
-4. Copy exectutable files from `./build/host/stage2-tools/<your hostname triple>/release`
-to `./build/host/stage2/bin/`. Note that you would need to do this every time you rebuilt `rust` repository.
-5. Copy cargo from another toolchain: `cp $(rustup which cargo) .build/<your hostname triple>/stage2/bin/cargo`
-   * Another option is to build it at step 3 and copy with other executables at step 4.
-6. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`.
-7. (Windows only) compile the build system: `rustc +stage2 -O build_system/main.rs -o y.exe`.
-8. You need to prefix every `./y.sh` (or `y` if you built `build_system/main.rs` as `y`) command by `rustup run stage2` to make cg_clif use your local changes in rustc.
-
+4. Copy cargo from a nightly toolchain: `cp $(rustup +nightly which cargo) ./build/host/stage2/bin/cargo`. Note that you would need to do this every time you rebuilt `rust` repository.
+5. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`.
+6. (Windows only) compile the build system: `rustc +stage2 -O build_system/main.rs -o y.exe`.
+7. You need to prefix every `./y.sh` (or `y` if you built `build_system/main.rs` as `y`) command by `rustup run stage2` to make cg_clif use your local changes in rustc.
   * `rustup run stage2 ./y.sh prepare`
   * `rustup run stage2 ./y.sh build`
   * (Optional) run tests: `rustup run stage2 ./y.sh test`
-9. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`.
+8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`.
 
 ## Configuration
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
index e434c36f992..d90111adf77 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
@@ -20,6 +20,8 @@ pub(crate) fn build_backend(
 
     let mut rustflags = rustflags_from_env("RUSTFLAGS");
 
+    rustflags.push("-Zallow-features=rustc_private".to_owned());
+
     if is_ci() {
         // Deny warnings on CI
         rustflags.push("-Dwarnings".to_owned());
diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs
index 798ae9dbd50..e8cf486e966 100644
--- a/compiler/rustc_codegen_cranelift/build_system/main.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/main.rs
@@ -55,7 +55,7 @@ enum CodegenBackend {
 }
 
 fn main() {
-    if env::var("RUST_BACKTRACE").is_err() {
+    if env::var_os("RUST_BACKTRACE").is_none() {
         env::set_var("RUST_BACKTRACE", "1");
     }
     env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 165296cb4a9..16e7a4bafae 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -122,10 +122,10 @@ impl GitRepo {
         if download_dir.exists() {
             let actual_hash = format!("{:016x}", hash_dir(&download_dir));
             if actual_hash == self.content_hash {
-                println!("[FRESH] {}", download_dir.display());
+                eprintln!("[FRESH] {}", download_dir.display());
                 return;
             } else {
-                println!(
+                eprintln!(
                     "Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Downloading again.",
                     download_dir = download_dir.display(),
                     content_hash = self.content_hash,
@@ -150,7 +150,7 @@ impl GitRepo {
 
         let actual_hash = format!("{:016x}", hash_dir(&download_dir));
         if actual_hash != self.content_hash {
-            println!(
+            eprintln!(
                 "Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}",
                 download_dir = download_dir.display(),
                 content_hash = self.content_hash,
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index e7bd8b1278c..95ff6b75422 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -9,7 +9,7 @@ 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, spawn_and_wait_with_input, CargoProject, Compiler, LogGroup};
+use crate::utils::{spawn_and_wait, CargoProject, Compiler, LogGroup};
 use crate::{CodegenBackend, SysrootKind};
 
 static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
@@ -101,13 +101,11 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
     TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
 ];
 
-// FIXME(rust-random/rand#1293): Newer rand versions fail to test on Windows. Update once this is
-// fixed.
 pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
     "rust-random",
     "rand",
-    "50b9a447410860af8d6db9a208c3576886955874",
-    "446203b96054891e",
+    "f3dd0b885c4597b9617ca79987a0dd899ab29fcb",
+    "3f869e4fcd602b66",
     "rand",
 );
 
@@ -116,8 +114,8 @@ pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir()
 pub(crate) static REGEX_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "regex",
-    "32fed9429eafba0ae92a64b01796a0c5a75b88c8",
-    "fcc4df7c5b902633",
+    "061ee815ef2c44101dba7b0b124600fcb03c1912",
+    "dc26aefbeeac03ca",
     "regex",
 );
 
@@ -126,8 +124,8 @@ pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir
 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "portable-simd",
-    "7c7dbe0c505ccbc02ff30c1e37381ab1d47bf46f",
-    "5bcc9c544f6fa7bd",
+    "4825b2a64d765317066948867e8714674419359b",
+    "8b188cc41f5af835",
     "portable-simd",
 );
 
@@ -180,40 +178,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
-        REGEX_REPO.patch(&runner.dirs);
-
-        REGEX.clean(&runner.dirs);
-
-        let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
-        build_cmd.arg("--example").arg("shootout-regex-dna");
-        spawn_and_wait(build_cmd);
-
-        if runner.is_native {
-            let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
-            run_cmd.arg("--example").arg("shootout-regex-dna");
-
-            let input = fs::read_to_string(
-                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
-            )
-            .unwrap();
-            let expected = fs::read_to_string(
-                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"),
-            )
-            .unwrap();
-
-            let output = spawn_and_wait_with_input(run_cmd, input);
-
-            let output_matches = expected.lines().eq(output.lines());
-            if !output_matches {
-                println!("Output files don't match!");
-                println!("Expected Output:\n{}", expected);
-                println!("Actual Output:\n{}", output);
-
-                std::process::exit(1);
-            }
-        }
-    }),
     TestCase::custom("test.regex", &|runner| {
         REGEX_REPO.patch(&runner.dirs);
 
@@ -223,7 +187,22 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
             let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
             // regex-capi and regex-debug don't have any tests. Nor do they contain any code
             // that is useful to test with cg_clif. Skip building them to reduce test time.
-            run_cmd.args(["-p", "regex", "-p", "regex-syntax", "--", "-q"]);
+            run_cmd.args([
+                "-p",
+                "regex",
+                "-p",
+                "regex-syntax",
+                "--release",
+                "--all-targets",
+                "--",
+                "-q",
+            ]);
+            spawn_and_wait(run_cmd);
+
+            let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
+            // don't run integration tests for regex-autonata. they take like 2min each without
+            // much extra coverage of simd usage.
+            run_cmd.args(["-p", "regex-automata", "--release", "--lib", "--", "-q"]);
             spawn_and_wait(run_cmd);
         } else {
             eprintln!("Cross-Compiling: Not running tests");
diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs
index 24624cdeab1..9f24c043a50 100644
--- a/compiler/rustc_codegen_cranelift/build_system/utils.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs
@@ -1,8 +1,8 @@
 use std::env;
 use std::fs;
-use std::io::{self, Write};
+use std::io;
 use std::path::{Path, PathBuf};
-use std::process::{self, Command, Stdio};
+use std::process::{self, Command};
 use std::sync::atomic::{AtomicBool, Ordering};
 
 use crate::path::{Dirs, RelPath};
@@ -47,7 +47,7 @@ impl Compiler {
                 self.runner = vec!["wine".to_owned()];
             }
             _ => {
-                println!("Unknown non-native platform");
+                eprintln!("Unknown non-native platform");
             }
         }
     }
@@ -197,7 +197,9 @@ pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
 
 #[track_caller]
 pub(crate) fn spawn_and_wait(mut cmd: Command) {
-    if !cmd.spawn().unwrap().wait().unwrap().success() {
+    let status = cmd.spawn().unwrap().wait().unwrap();
+    if !status.success() {
+        eprintln!("{cmd:?} exited with status {:?}", status);
         process::exit(1);
     }
 }
@@ -207,38 +209,17 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) {
 pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) {
     for i in 1..tries + 1 {
         if i != 1 {
-            println!("Command failed. Attempt {i}/{tries}:");
+            eprintln!("Command failed. Attempt {i}/{tries}:");
         }
         if cmd.spawn().unwrap().wait().unwrap().success() {
             return;
         }
         std::thread::sleep(std::time::Duration::from_secs(i * 5));
     }
-    println!("The command has failed after {tries} attempts.");
+    eprintln!("The command has failed after {tries} attempts.");
     process::exit(1);
 }
 
-#[track_caller]
-pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String {
-    let mut child = cmd
-        .stdin(Stdio::piped())
-        .stdout(Stdio::piped())
-        .spawn()
-        .expect("Failed to spawn child process");
-
-    let mut stdin = child.stdin.take().expect("Failed to open stdin");
-    std::thread::spawn(move || {
-        stdin.write_all(input.as_bytes()).expect("Failed to write to stdin");
-    });
-
-    let output = child.wait_with_output().expect("Failed to read stdout");
-    if !output.status.success() {
-        process::exit(1);
-    }
-
-    String::from_utf8(output.stdout).unwrap()
-}
-
 pub(crate) fn remove_dir_if_exists(path: &Path) {
     match fs::remove_dir_all(&path) {
         Ok(()) => {}
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index fa1c9f4259c..7ff805e58d9 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -46,6 +46,5 @@ aot.issue-59326
 testsuite.extended_sysroot
 test.rust-random/rand
 test.libcore
-test.regex-shootout-regex-dna
 test.regex
 test.portable-simd
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 34c7e44b288..934e4b1786f 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -685,6 +685,12 @@ pub macro cfg() {
 
 #[rustc_builtin_macro]
 #[rustc_macro_transparency = "semitransparent"]
+pub macro asm() {
+    /* compiler built-in */
+}
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
 pub macro global_asm() {
     /* compiler built-in */
 }
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Allow-internal-features.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Allow-internal-features.patch
deleted file mode 100644
index 87252df1eab..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Allow-internal-features.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From fcf75306d88e533b83eaff3f8d0ab9f307e8a84d Mon Sep 17 00:00:00 2001
-From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
-Date: Wed, 9 Aug 2023 10:01:17 +0000
-Subject: [PATCH] Allow internal features
-
----
- crates/core_simd/src/lib.rs | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs
-index fde406b..b386116 100644
---- a/crates/core_simd/src/lib.rs
-+++ b/crates/core_simd/src/lib.rs
-@@ -19,6 +19,7 @@
- #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
- #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
- #![unstable(feature = "portable_simd", issue = "86656")]
-+#![allow(internal_features)]
- //! Portable SIMD module.
- 
- #[path = "mod.rs"]
--- 
-2.34.1
-
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch b/compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch
new file mode 100644
index 00000000000..e6ebdcec783
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch
@@ -0,0 +1,25 @@
+From 5d4afb8d807d181038b6a004d17ed055a8d191b2 Mon Sep 17 00:00:00 2001
+From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
+Date: Mon, 2 Oct 2023 13:59:00 +0000
+Subject: [PATCH] Ignore test which gets miscompiled with llvm sysroot
+
+---
+ regex-automata/src/util/pool.rs | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/regex-automata/src/util/pool.rs b/regex-automata/src/util/pool.rs
+index c03d7b0..28b233b 100644
+--- a/regex-automata/src/util/pool.rs
++++ b/regex-automata/src/util/pool.rs
+@@ -1081,6 +1081,8 @@ mod tests {
+     // into the pool. This in turn resulted in this test producing a data race.
+     #[cfg(feature = "std")]
+     #[test]
++    // FIXME(rustc_codegen_cranelift#1395) miscompilation of thread::scope with LLVM sysroot
++    #[ignore]
+     fn thread_owner_sync() {
+         let pool = Pool::new(|| vec!['a']);
+         {
+-- 
+2.34.1
+
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 a650e10110b..be29ae09bcf 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
@@ -19,9 +19,9 @@ index 897a5e9..331f66f 100644
  #![feature(const_option_ext)]
  #![feature(const_result)]
 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
+ #![cfg_attr(test, feature(cfg_match))]
  #![feature(int_roundings)]
  #![feature(slice_group_by)]
- #![feature(split_array)]
 diff --git a/atomic.rs b/atomic.rs
 index b735957..ea728b6 100644
 --- a/atomic.rs
diff --git a/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml b/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml
index e7db1fd2c7f..5c9dc7b361f 100644
--- a/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml
@@ -16,9 +16,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bumpalo"
-version = "3.13.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "byteorder"
@@ -55,33 +55,33 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.63"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
 dependencies = [
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "log"
-version = "0.4.18"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.17.2"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
 name = "ppv-lite86"
@@ -91,9 +91,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.59"
+version = "1.0.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
+checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
 dependencies = [
  "unicode-ident",
 ]
@@ -114,9 +114,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.28"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -181,9 +181,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.18"
+version = "2.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -199,15 +199,15 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.9"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -215,9 +215,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
 dependencies = [
  "bumpalo",
  "log",
@@ -230,9 +230,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.36"
+version = "0.4.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
+checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -242,9 +242,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -252,9 +252,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -265,15 +265,15 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
 [[package]]
 name = "wasm-bindgen-test"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e636f3a428ff62b3742ebc3c70e254dfe12b8c2b469d688ea59cdd4abcf502"
+checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671"
 dependencies = [
  "console_error_panic_hook",
  "js-sys",
@@ -285,9 +285,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-test-macro"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f18c1fad2f7c4958e7bcce014fa212f59a65d5e3721d0f77e6c0b27ede936ba3"
+checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -295,9 +295,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.63"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
diff --git a/compiler/rustc_codegen_cranelift/patches/rand-lock.toml b/compiler/rustc_codegen_cranelift/patches/rand-lock.toml
index 66c515731c5..aacf3653c16 100644
--- a/compiler/rustc_codegen_cranelift/patches/rand-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/rand-lock.toml
@@ -3,6 +3,32 @@
 version = 3
 
 [[package]]
+name = "aho-corasick"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi 0.1.19",
+ "libc",
+ "winapi",
+]
+
+[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -29,12 +55,114 @@ dependencies = [
 ]
 
 [[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "ciborium"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+dependencies = [
+ "bitflags",
+ "clap_lex",
+ "indexmap",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "criterion"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
+dependencies = [
+ "anes",
+ "atty",
+ "cast",
+ "ciborium",
+ "clap",
+ "criterion-plot",
+ "itertools",
+ "lazy_static",
+ "num-traits",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
+dependencies = [
+ "cast",
+ "itertools",
+]
+
+[[package]]
 name = "crossbeam-channel"
 version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -57,9 +185,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.14"
+version = "0.9.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
 dependencies = [
  "autocfg",
  "cfg-if",
@@ -70,14 +198,49 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.15"
+version = "0.8.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
 dependencies = [
  "cfg-if",
 ]
 
 [[package]]
+name = "darling"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
 name = "easy-cast"
 version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -88,9 +251,9 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.8.1"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
 
 [[package]]
 name = "float-ord"
@@ -99,10 +262,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d"
 
 [[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
 name = "getrandom"
-version = "0.2.9"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
  "cfg-if",
  "libc",
@@ -110,25 +279,83 @@ dependencies = [
 ]
 
 [[package]]
+name = "half"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
 name = "hermit-abi"
-version = "0.2.6"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 dependencies = [
  "libc",
 ]
 
 [[package]]
+name = "hermit-abi"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
 name = "itoa"
-version = "1.0.6"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+
+[[package]]
+name = "js-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.144"
+version = "0.2.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
+checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
 
 [[package]]
 name = "libm"
@@ -138,24 +365,30 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
 
 [[package]]
 name = "log"
-version = "0.4.18"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
 
 [[package]]
 name = "memoffset"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
 dependencies = [
  "autocfg",
  "libm",
@@ -163,15 +396,61 @@ dependencies = [
 
 [[package]]
 name = "num_cpus"
-version = "1.15.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.3.2",
  "libc",
 ]
 
 [[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "oorandom"
+version = "11.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
+
+[[package]]
+name = "os_str_bytes"
+version = "6.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
+
+[[package]]
+name = "plotters"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
+dependencies = [
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "plotters-backend"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
+
+[[package]]
+name = "plotters-svg"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
+dependencies = [
+ "plotters-backend",
+]
+
+[[package]]
 name = "ppv-lite86"
 version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -179,18 +458,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.59"
+version = "1.0.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
+checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.28"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -200,6 +479,7 @@ name = "rand"
 version = "0.9.0"
 dependencies = [
  "bincode",
+ "criterion",
  "libc",
  "log",
  "rand_chacha",
@@ -236,6 +516,7 @@ dependencies = [
  "rand",
  "rand_pcg",
  "serde",
+ "serde_with",
  "special",
 ]
 
@@ -271,42 +552,80 @@ dependencies = [
 ]
 
 [[package]]
+name = "regex"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
+
+[[package]]
 name = "ryu"
-version = "1.0.13"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
 
 [[package]]
 name = "scopeguard"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.163"
+version = "1.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
+checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.163"
+version = "1.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
+checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.37",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.96"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
+checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
 dependencies = [
  "itoa",
  "ryu",
@@ -314,6 +633,28 @@ dependencies = [
 ]
 
 [[package]]
+name = "serde_with"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
+dependencies = [
+ "serde",
+ "serde_with_macros",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
 name = "special"
 version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -323,10 +664,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
 name = "syn"
-version = "2.0.18"
+version = "2.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -334,13 +692,134 @@ dependencies = [
 ]
 
 [[package]]
+name = "textwrap"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
 name = "unicode-ident"
-version = "1.0.9"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "walkdir"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
 
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.37",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.37",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+
+[[package]]
+name = "web-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/compiler/rustc_codegen_cranelift/patches/regex-lock.toml b/compiler/rustc_codegen_cranelift/patches/regex-lock.toml
index 0e4a33b90ea..e0df6f9ae26 100644
--- a/compiler/rustc_codegen_cranelift/patches/regex-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/regex-lock.toml
@@ -4,51 +4,49 @@ version = 3
 
 [[package]]
 name = "aho-corasick"
-version = "0.7.20"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
 dependencies = [
+ "log",
  "memchr",
 ]
 
 [[package]]
-name = "bitflags"
-version = "1.3.2"
+name = "anyhow"
+version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
 
 [[package]]
-name = "bzip2"
-version = "0.3.3"
+name = "arbitrary"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
+checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
 dependencies = [
- "bzip2-sys",
- "libc",
+ "derive_arbitrary",
 ]
 
 [[package]]
-name = "bzip2-sys"
-version = "0.1.11+1.0.8"
+name = "atty"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "cc",
+ "hermit-abi",
  "libc",
- "pkg-config",
+ "winapi",
 ]
 
 [[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
+name = "bstr"
+version = "1.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a"
+dependencies = [
+ "memchr",
+ "serde",
+]
 
 [[package]]
 name = "cfg-if"
@@ -57,114 +55,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
-name = "docopt"
-version = "1.1.1"
+name = "derive_arbitrary"
+version = "1.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f"
+checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8"
 dependencies = [
- "lazy_static",
- "regex 1.8.3",
- "serde",
- "strsim",
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
-name = "filetime"
-version = "0.2.21"
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
+name = "env_logger"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
 dependencies = [
- "cfg-if 1.0.0",
- "libc",
- "redox_syscall",
- "windows-sys",
+ "atty",
+ "humantime",
+ "log",
+ "termcolor",
 ]
 
 [[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
 name = "getrandom"
-version = "0.2.9"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
  "libc",
  "wasi",
 ]
 
 [[package]]
-name = "lazy_static"
-version = "1.4.0"
+name = "hashbrown"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
 
 [[package]]
-name = "libc"
-version = "0.2.144"
+name = "hermit-abi"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
-
-[[package]]
-name = "libpcre-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ff3dd28ba96d6fe6752882f2f1b25ba8e1646448e79042442347cf3a92a6666"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 dependencies = [
- "bzip2",
  "libc",
- "pkg-config",
- "tar",
 ]
 
 [[package]]
-name = "memchr"
-version = "2.5.0"
+name = "humantime"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
-name = "memmap"
-version = "0.6.2"
+name = "indexmap"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
 dependencies = [
- "libc",
- "winapi",
+ "equivalent",
+ "hashbrown",
 ]
 
 [[package]]
-name = "onig"
-version = "3.2.2"
+name = "lexopt"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401"
+
+[[package]]
+name = "libc"
+version = "0.2.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5eeb268a4620c74ea5768c6d2ccd492d60a47a8754666b91a46bfc35cd4d1ba"
+checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
 dependencies = [
- "bitflags",
- "lazy_static",
- "libc",
- "onig_sys",
+ "log",
 ]
 
 [[package]]
-name = "onig_sys"
-version = "68.2.1"
+name = "memmap2"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "195ebddbb56740be48042ca117b8fb6e0d99fe392191a9362d82f5f69e510379"
+checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
 dependencies = [
- "cc",
  "libc",
- "pkg-config",
 ]
 
 [[package]]
-name = "pkg-config"
-version = "0.3.27"
+name = "once_cell"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.59"
+version = "1.0.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
+checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
 dependencies = [
  "unicode-ident",
 ]
@@ -180,9 +193,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.28"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -206,95 +219,101 @@ dependencies = [
 ]
 
 [[package]]
-name = "redox_syscall"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
 name = "regex"
-version = "1.7.2"
+version = "1.9.5"
 dependencies = [
  "aho-corasick",
- "lazy_static",
+ "anyhow",
+ "doc-comment",
+ "env_logger",
  "memchr",
+ "once_cell",
  "quickcheck",
- "rand",
- "regex-syntax 0.6.29",
+ "regex-automata",
+ "regex-syntax",
+ "regex-test",
 ]
 
 [[package]]
-name = "regex"
-version = "1.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
+name = "regex-automata"
+version = "0.3.8"
 dependencies = [
- "regex-syntax 0.7.2",
+ "aho-corasick",
+ "anyhow",
+ "bstr",
+ "doc-comment",
+ "env_logger",
+ "log",
+ "memchr",
+ "quickcheck",
+ "regex-syntax",
+ "regex-test",
 ]
 
 [[package]]
-name = "regex-benchmark"
+name = "regex-cli"
 version = "0.1.0"
 dependencies = [
- "cc",
- "cfg-if 0.1.10",
- "docopt",
- "lazy_static",
- "libc",
- "libpcre-sys",
- "memmap",
- "onig",
- "pkg-config",
- "regex 1.7.2",
- "regex-syntax 0.6.29",
- "serde",
+ "anyhow",
+ "bstr",
+ "lexopt",
+ "log",
+ "memmap2",
+ "regex",
+ "regex-automata",
+ "regex-lite",
+ "regex-syntax",
+ "tabwriter",
+ "textwrap",
 ]
 
 [[package]]
-name = "regex-debug"
+name = "regex-lite"
 version = "0.1.0"
 dependencies = [
- "docopt",
- "regex 1.7.2",
- "regex-syntax 0.6.29",
- "serde",
+ "anyhow",
+ "regex-test",
 ]
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.29"
+version = "0.7.5"
+dependencies = [
+ "arbitrary",
+]
 
 [[package]]
-name = "regex-syntax"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
+name = "regex-test"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "bstr",
+ "serde",
+ "toml",
+]
 
 [[package]]
 name = "rure"
 version = "0.2.2"
 dependencies = [
  "libc",
- "regex 1.7.2",
+ "regex",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.163"
+version = "1.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
+checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.163"
+version = "1.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
+checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -302,16 +321,19 @@ dependencies = [
 ]
 
 [[package]]
-name = "strsim"
-version = "0.10.0"
+name = "serde_spanned"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "syn"
-version = "2.0.18"
+version = "2.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -319,121 +341,117 @@ dependencies = [
 ]
 
 [[package]]
-name = "tar"
-version = "0.4.38"
+name = "tabwriter"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
+checksum = "08e1173ee641651a3095fe95d86ae314cd1f959888097debce3e0f9ca532eef1"
 dependencies = [
- "filetime",
- "libc",
- "xattr",
+ "unicode-width",
 ]
 
 [[package]]
-name = "unicode-ident"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
+name = "termcolor"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
 dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
+ "winapi-util",
 ]
 
 [[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
+name = "textwrap"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "toml"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
 
 [[package]]
-name = "windows-sys"
-version = "0.48.0"
+name = "toml_datetime"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
 dependencies = [
- "windows-targets",
+ "serde",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.48.0"
+name = "toml_edit"
+version = "0.19.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+name = "unicode-ident"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.0"
+name = "unicode-width"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.48.0"
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.48.0"
+name = "winapi"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
 
 [[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.0"
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+name = "winapi-util"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.0"
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
-name = "xattr"
-version = "0.2.3"
+name = "winnow"
+version = "0.5.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
+checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
 dependencies = [
- "libc",
+ "memchr",
 ]
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
index 5b79d6569bb..de89c4f5eff 100644
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
@@ -174,9 +174,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.146"
+version = "0.2.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
+checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -256,6 +256,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "r-efi"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "575fc2d9b3da54adbdfaddf6eca48fec256d977c8630a1750b8991347d1ac911"
+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"
@@ -340,6 +361,7 @@ version = "0.0.0"
 dependencies = [
  "addr2line",
  "alloc",
+ "cc",
  "cfg-if",
  "compiler_builtins",
  "core",
@@ -353,6 +375,8 @@ dependencies = [
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
+ "r-efi",
+ "r-efi-alloc",
  "rand",
  "rand_xorshift",
  "rustc-demangle",
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 2cc5d7777a6..86ef127badd 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-09-06"
+channel = "nightly-2023-10-09"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index f09b9ef12de..60ac6bc9951 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 set -e
 
-./y.sh build --no-unstable-features
+./y.sh build
 
 echo "[SETUP] Rust fork"
 git clone https://github.com/rust-lang/rust.git || true
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 3fc462a39cc..3b2a12ec028 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -11,22 +11,17 @@ pushd rust
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
 rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "lto|// needs-asm-support" tests/{codegen-units,ui,incremental}); do
+for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
-for test in tests/run-make/**/Makefile; do
-  if rg "# needs-asm-support" $test >/dev/null; then
-    rm -r $(dirname $test)
-  fi
-done
-
 for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do
   rm $test
 done
 
 git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
 git checkout -- tests/ui/proc-macro/pretty-print-hack/
+git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs
 rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 
 # missing features
@@ -35,8 +30,9 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 rm -r tests/run-make/comment-section # cg_clif doesn't yet write the .comment section
 
 # requires stack unwinding
-# FIXME add needs-unwind to this test
+# FIXME add needs-unwind to these tests
 rm -r tests/run-make/libtest-junit
+rm tests/ui/asm/may_unwind.rs
 
 # extra warning about -Cpanic=abort for proc macros
 rm tests/ui/proc-macro/crt-static.rs
@@ -77,6 +73,8 @@ rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported
 rm -r tests/run-make/target-specs # i686 not supported by Cranelift
 rm -r tests/run-make/mismatching-target-triples # same
 rm -r tests/run-make/use-extern-for-plugins # same
+rm tests/ui/asm/x86_64/issue-82869.rs # vector regs in inline asm not yet supported
+rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
 
 # requires LTO
 rm -r tests/run-make/cdylib
@@ -130,6 +128,7 @@ rm tests/ui/consts/issue-73976-monomorphic.rs # same
 rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same
 rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs # same
 rm tests/ui/consts/issue-94675.rs # same
+rm tests/ui/associated-types/issue-85103-layout-debug.rs # same
 
 # rustdoc-clif passes extra args, suppressing the help message when no args are passed
 rm -r tests/run-make/issue-88756-default-output
@@ -154,9 +153,12 @@ rm -r tests/run-make/output-type-permutations # same
 rm -r tests/run-make/used # same
 rm -r tests/run-make/no-alloc-shim
 rm -r tests/run-make/emit-to-stdout
+rm -r tests/run-make/compressed-debuginfo
 
 rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported
 
+rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug with Generator's
+
 # bugs in the test suite
 # ======================
 rm tests/ui/backtrace.rs # TODO warning
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 5c7d7b20c5d..c75ad852f82 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -6,6 +6,7 @@ mod returning;
 
 use std::borrow::Cow;
 
+use cranelift_codegen::ir::{AbiParam, SigRef};
 use cranelift_module::ModuleError;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
@@ -13,12 +14,9 @@ use rustc_session::Session;
 use rustc_target::abi::call::{Conv, FnAbi};
 use rustc_target::spec::abi::Abi;
 
-use cranelift_codegen::ir::{AbiParam, SigRef};
-
 use self::pass_mode::*;
-use crate::prelude::*;
-
 pub(crate) use self::returning::codegen_return;
+use crate::prelude::*;
 
 fn clif_sig_from_fn_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 0d16da48067..7c9f8c1051c 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -1,14 +1,14 @@
 //! Argument passing
 
-use crate::prelude::*;
-use crate::value_and_place::assert_assignable;
-
 use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
 use rustc_target::abi::call::{
     ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind,
 };
 use smallvec::{smallvec, SmallVec};
 
+use crate::prelude::*;
+use crate::value_and_place::assert_assignable;
+
 pub(super) trait ArgAbiExt<'tcx> {
     fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>;
     fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>);
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index 646fb4a3cdc..0799a22c6e1 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -1,10 +1,10 @@
 //! Return value handling
 
-use crate::prelude::*;
-
 use rustc_target::abi::call::{ArgAbi, PassMode};
 use smallvec::{smallvec, SmallVec};
 
+use crate::prelude::*;
+
 /// Return a place where the return value of the current function can be written to. If necessary
 /// this adds an extra parameter pointing to where the return value needs to be stored.
 pub(super) fn codegen_return_param<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index 4e4c595de82..e8af3e8c255 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -1,8 +1,6 @@
 //! Allocator shim
 // Adapted from rustc
 
-use crate::prelude::*;
-
 use rustc_ast::expand::allocator::{
     alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
     ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
@@ -10,6 +8,8 @@ use rustc_ast::expand::allocator::{
 use rustc_codegen_ssa::base::allocator_kind_for_codegen;
 use rustc_session::config::OomStrategy;
 
+use crate::prelude::*;
+
 /// Returns whether an allocator shim was created
 pub(crate) fn codegen(
     tcx: TyCtxt<'_>,
diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs
index 359d581c153..321612238ea 100644
--- a/compiler/rustc_codegen_cranelift/src/analyze.rs
+++ b/compiler/rustc_codegen_cranelift/src/analyze.rs
@@ -1,11 +1,11 @@
 //! SSA analysis
 
-use crate::prelude::*;
-
 use rustc_index::IndexVec;
 use rustc_middle::mir::StatementKind::*;
 use rustc_middle::ty::Ty;
 
+use crate::prelude::*;
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub(crate) enum SsaKind {
     NotSsa,
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 0c0a1e80a41..ac7389792c8 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -1,15 +1,14 @@
 //! Codegen of a single function
 
+use cranelift_codegen::ir::UserFuncName;
+use cranelift_codegen::CodegenError;
+use cranelift_module::ModuleError;
 use rustc_ast::InlineAsmOptions;
 use rustc_index::IndexVec;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 
-use cranelift_codegen::ir::UserFuncName;
-use cranelift_codegen::CodegenError;
-use cranelift_module::ModuleError;
-
 use crate::constant::ConstantCx;
 use crate::debuginfo::FunctionDebugContext;
 use crate::prelude::*;
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 6bf3a866ba4..7e027c5f1b3 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -129,8 +129,8 @@ pub(crate) fn clif_int_or_float_cast(
             let (min, max) = match (to_ty, to_signed) {
                 (types::I8, false) => (0, i64::from(u8::MAX)),
                 (types::I16, false) => (0, i64::from(u16::MAX)),
-                (types::I8, true) => (i64::from(i8::MIN), i64::from(i8::MAX)),
-                (types::I16, true) => (i64::from(i16::MIN), i64::from(i16::MAX)),
+                (types::I8, true) => (i64::from(i8::MIN as u32), i64::from(i8::MAX as u32)),
+                (types::I16, true) => (i64::from(i16::MIN as u32), i64::from(i16::MAX as u32)),
                 _ => unreachable!(),
             };
             let min_val = fx.bcx.ins().iconst(types::I32, min);
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 359b430b4e5..8958369267e 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -1,6 +1,5 @@
 use cranelift_codegen::isa::TargetFrontendConfig;
 use gimli::write::FileId;
-
 use rustc_data_structures::sync::Lrc;
 use rustc_index::IndexVec;
 use rustc_middle::ty::layout::{
@@ -204,9 +203,9 @@ pub(crate) fn type_min_max_value(
         (types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => {
             0i64
         }
-        (types::I8, true) => i64::from(i8::MIN),
-        (types::I16, true) => i64::from(i16::MIN),
-        (types::I32, true) => i64::from(i32::MIN),
+        (types::I8, true) => i64::from(i8::MIN as u8),
+        (types::I16, true) => i64::from(i16::MIN as u16),
+        (types::I32, true) => i64::from(i32::MIN as u32),
         (types::I64, true) => i64::MIN,
         _ => unreachable!(),
     };
@@ -216,9 +215,9 @@ pub(crate) fn type_min_max_value(
         (types::I16, false) => i64::from(u16::MAX),
         (types::I32, false) => i64::from(u32::MAX),
         (types::I64, false) => u64::MAX as i64,
-        (types::I8, true) => i64::from(i8::MAX),
-        (types::I16, true) => i64::from(i16::MAX),
-        (types::I32, true) => i64::from(i32::MAX),
+        (types::I8, true) => i64::from(i8::MAX as u8),
+        (types::I16, true) => i64::from(i16::MAX as u16),
+        (types::I32, true) => i64::from(i32::MAX as u32),
         (types::I64, true) => i64::MAX,
         _ => unreachable!(),
     };
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index d2b928db7d4..20f2ee4c76a 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -1,8 +1,7 @@
 use std::sync::{Arc, Condvar, Mutex};
 
-use rustc_session::Session;
-
 use jobserver::HelperThread;
+use rustc_session::Session;
 
 // FIXME don't panic when a worker thread panics
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 14b10ed8b9a..1cb6fa07723 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -1,12 +1,11 @@
 //! Handling of `static`s, `const`s and promoted allocations
 
+use cranelift_module::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar};
 use rustc_middle::mir::ConstValue;
 
-use cranelift_module::*;
-
 use crate::prelude::*;
 
 pub(crate) struct ConstantCx {
@@ -101,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
                 if fx.clif_type(layout.ty).is_some() {
                     return CValue::const_val(fx, layout, int);
                 } else {
-                    let raw_val = int.to_bits(int.size()).unwrap();
+                    let raw_val = int.size().truncate(int.to_bits(int.size()).unwrap());
                     let val = match int.size().bytes() {
                         1 => fx.bcx.ins().iconst(types::I8, raw_val as i64),
                         2 => fx.bcx.ins().iconst(types::I16, raw_val as i64),
@@ -187,8 +186,7 @@ pub(crate) fn codegen_const_value<'tcx>(
         ConstValue::Slice { data, meta } => {
             let alloc_id = fx.tcx.reserve_and_set_memory_alloc(data);
             let ptr = pointer_for_allocation(fx, alloc_id).get_addr(fx);
-            // FIXME: the `try_from` here can actually fail, e.g. for very long ZST slices.
-            let len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(meta).unwrap());
+            let len = fx.bcx.ins().iconst(fx.pointer_type, meta as i64);
             CValue::by_val_pair(ptr, len, layout)
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
index c4a5627e662..81b819a5546 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
@@ -1,10 +1,9 @@
 //! Write the debuginfo into an object file.
 
 use cranelift_object::ObjectProduct;
-use rustc_data_structures::fx::FxHashMap;
-
 use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
 use gimli::{RunTimeEndian, SectionId};
+use rustc_data_structures::fx::FxHashMap;
 
 use super::object::WriteDebugInfo;
 use super::DebugContext;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
index b19b935a0fe..d00d19f9a80 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
@@ -3,20 +3,18 @@
 use std::ffi::OsStr;
 use std::path::{Component, Path};
 
-use crate::debuginfo::FunctionDebugContext;
-use crate::prelude::*;
-
-use rustc_data_structures::sync::Lrc;
-use rustc_span::{
-    FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
-};
-
 use cranelift_codegen::binemit::CodeOffset;
 use cranelift_codegen::MachSrcLoc;
-
 use gimli::write::{
     Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable,
 };
+use rustc_data_structures::sync::Lrc;
+use rustc_span::{
+    FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
+};
+
+use crate::debuginfo::FunctionDebugContext;
+use crate::prelude::*;
 
 // OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
 fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 8a4b1cccf14..9e78cc259ce 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -5,11 +5,8 @@ mod line_info;
 mod object;
 mod unwind;
 
-use crate::prelude::*;
-
 use cranelift_codegen::ir::Endianness;
 use cranelift_codegen::isa::TargetIsa;
-
 use gimli::write::{
     Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList,
     UnitEntryId,
@@ -17,8 +14,9 @@ use gimli::write::{
 use gimli::{Encoding, Format, LineEncoding, RunTimeEndian};
 use indexmap::IndexSet;
 
-pub(crate) use emit::{DebugReloc, DebugRelocName};
-pub(crate) use unwind::UnwindContext;
+pub(crate) use self::emit::{DebugReloc, DebugRelocName};
+pub(crate) use self::unwind::UnwindContext;
+use crate::prelude::*;
 
 pub(crate) fn producer() -> String {
     format!(
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
index 9dc9b2cf9f8..f1840a7bf73 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
@@ -1,12 +1,9 @@
-use rustc_data_structures::fx::FxHashMap;
-
 use cranelift_module::FuncId;
 use cranelift_object::ObjectProduct;
-
+use gimli::SectionId;
 use object::write::{Relocation, StandardSegment};
 use object::{RelocationEncoding, SectionKind};
-
-use gimli::SectionId;
+use rustc_data_structures::fx::FxHashMap;
 
 use crate::debuginfo::{DebugReloc, DebugRelocName};
 
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index 493359c743f..35278e6fb29 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -1,15 +1,13 @@
 //! Unwind info generation (`.eh_frame`)
 
-use crate::prelude::*;
-
 use cranelift_codegen::ir::Endianness;
 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
-
 use cranelift_object::ObjectProduct;
 use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
 use gimli::RunTimeEndian;
 
 use super::object::WriteDebugInfo;
+use crate::prelude::*;
 
 pub(crate) struct UnwindContext {
     endian: RunTimeEndian,
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 3e93830951c..cc2f5d72714 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -6,6 +6,7 @@ use std::path::PathBuf;
 use std::sync::Arc;
 use std::thread::JoinHandle;
 
+use cranelift_object::{ObjectBuilder, ObjectModule};
 use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
 use rustc_data_structures::profiling::SelfProfilerRef;
@@ -17,8 +18,6 @@ use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{DebugInfo, OutputFilenames, OutputType};
 use rustc_session::Session;
 
-use cranelift_object::{ObjectBuilder, ObjectModule};
-
 use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
 use crate::global_asm::GlobalAsmConfig;
 use crate::{prelude::*, BackendConfig};
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 1c606494f38..6ee65d12c73 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -6,13 +6,12 @@ use std::ffi::CString;
 use std::os::raw::{c_char, c_int};
 use std::sync::{mpsc, Mutex, OnceLock};
 
+use cranelift_jit::{JITBuilder, JITModule};
 use rustc_codegen_ssa::CrateInfo;
 use rustc_middle::mir::mono::MonoItem;
 use rustc_session::Session;
 use rustc_span::Symbol;
 
-use cranelift_jit::{JITBuilder, JITModule};
-
 use crate::{prelude::*, BackendConfig};
 use crate::{CodegenCx, CodegenMode};
 
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index baadd7a9e81..ebd9b728d90 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -9,16 +9,22 @@ use std::sync::Arc;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::{InlineAsmOperand, ItemId};
 use rustc_session::config::{OutputFilenames, OutputType};
+use rustc_target::asm::InlineAsmArch;
 
 use crate::prelude::*;
 
 pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
     let item = tcx.hir().item(item_id);
     if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
-        if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
-            global_asm.push_str("\n.intel_syntax noprefix\n");
-        } else {
-            global_asm.push_str("\n.att_syntax\n");
+        let is_x86 =
+            matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
+
+        if is_x86 {
+            if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
+                global_asm.push_str("\n.intel_syntax noprefix\n");
+            } else {
+                global_asm.push_str("\n.att_syntax\n");
+            }
         }
         for piece in asm.template {
             match *piece {
@@ -65,7 +71,11 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
                 }
             }
         }
-        global_asm.push_str("\n.att_syntax\n\n");
+
+        global_asm.push('\n');
+        if is_x86 {
+            global_asm.push_str(".att_syntax\n\n");
+        }
     } else {
         bug!("Expected GlobalAsm found {:?}", item);
     }
@@ -115,11 +125,12 @@ pub(crate) fn compile_global_asm(
     }
 
     // Remove all LLVM style comments
-    let global_asm = global_asm
+    let mut global_asm = global_asm
         .lines()
         .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line })
         .collect::<Vec<_>>()
         .join("\n");
+    global_asm.push('\n');
 
     let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));
 
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 50bbf8105fd..dd2127d554d 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -1,13 +1,14 @@
 //! Codegen of `asm!` invocations.
 
-use crate::prelude::*;
-
 use std::fmt::Write;
 
 use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir::InlineAsmOperand;
 use rustc_span::sym;
 use rustc_target::asm::*;
+use target_lexicon::BinaryFormat;
+
+use crate::prelude::*;
 
 enum CInlineAsmOperand<'tcx> {
     In {
@@ -43,7 +44,9 @@ pub(crate) fn codegen_inline_asm<'tcx>(
 ) {
     // FIXME add .eh_frame unwind info directives
 
-    if !template.is_empty() {
+    if !template.is_empty()
+        && (cfg!(not(feature = "inline_asm")) || fx.tcx.sess.target.is_like_windows)
+    {
         // Used by panic_abort
         if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
             fx.bcx.ins().trap(TrapCode::User(1));
@@ -589,11 +592,29 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
     }
 
     fn generate_asm_wrapper(&self, asm_name: &str) -> String {
+        let binary_format = crate::target_triple(self.tcx.sess).binary_format;
+
         let mut generated_asm = String::new();
-        writeln!(generated_asm, ".globl {}", asm_name).unwrap();
-        writeln!(generated_asm, ".type {},@function", asm_name).unwrap();
-        writeln!(generated_asm, ".section .text.{},\"ax\",@progbits", asm_name).unwrap();
-        writeln!(generated_asm, "{}:", asm_name).unwrap();
+        match binary_format {
+            BinaryFormat::Elf => {
+                writeln!(generated_asm, ".globl {}", asm_name).unwrap();
+                writeln!(generated_asm, ".type {},@function", asm_name).unwrap();
+                writeln!(generated_asm, ".section .text.{},\"ax\",@progbits", asm_name).unwrap();
+                writeln!(generated_asm, "{}:", asm_name).unwrap();
+            }
+            BinaryFormat::Macho => {
+                writeln!(generated_asm, ".globl _{}", asm_name).unwrap();
+                writeln!(generated_asm, "_{}:", asm_name).unwrap();
+            }
+            BinaryFormat::Coff => {
+                writeln!(generated_asm, ".globl {}", asm_name).unwrap();
+                writeln!(generated_asm, "{}:", asm_name).unwrap();
+            }
+            _ => self
+                .tcx
+                .sess
+                .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")),
+        }
 
         let is_x86 = matches!(self.arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
 
@@ -690,8 +711,19 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
         if is_x86 {
             generated_asm.push_str(".att_syntax\n");
         }
-        writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap();
-        generated_asm.push_str(".text\n");
+
+        match binary_format {
+            BinaryFormat::Elf => {
+                writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap();
+                generated_asm.push_str(".text\n");
+            }
+            BinaryFormat::Macho | BinaryFormat::Coff => {}
+            _ => self
+                .tcx
+                .sess
+                .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")),
+        }
+
         generated_asm.push_str("\n\n");
 
         generated_asm
@@ -699,25 +731,19 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
 
     fn prologue(generated_asm: &mut String, arch: InlineAsmArch) {
         match arch {
-            InlineAsmArch::X86 => {
-                generated_asm.push_str("    push ebp\n");
-                generated_asm.push_str("    mov ebp,[esp+8]\n");
-            }
             InlineAsmArch::X86_64 => {
                 generated_asm.push_str("    push rbp\n");
-                generated_asm.push_str("    mov rbp,rdi\n");
-            }
-            InlineAsmArch::RiscV32 => {
-                generated_asm.push_str("    addi sp, sp, -8\n");
-                generated_asm.push_str("    sw ra, 4(sp)\n");
-                generated_asm.push_str("    sw s0, 0(sp)\n");
-                generated_asm.push_str("    mv s0, a0\n");
-            }
-            InlineAsmArch::RiscV64 => {
-                generated_asm.push_str("    addi sp, sp, -16\n");
-                generated_asm.push_str("    sd ra, 8(sp)\n");
-                generated_asm.push_str("    sd s0, 0(sp)\n");
-                generated_asm.push_str("    mv s0, a0\n");
+                generated_asm.push_str("    mov rbp,rsp\n");
+                generated_asm.push_str("    push rbx\n"); // rbx is callee saved
+                // rbx is reserved by LLVM for the "base pointer", so rustc doesn't allow using it
+                generated_asm.push_str("    mov rbx,rdi\n");
+            }
+            InlineAsmArch::AArch64 => {
+                generated_asm.push_str("    stp fp, lr, [sp, #-32]!\n");
+                generated_asm.push_str("    mov fp, sp\n");
+                generated_asm.push_str("    str x19, [sp, #24]\n"); // x19 is callee saved
+                // x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it
+                generated_asm.push_str("    mov x19, x0\n");
             }
             _ => unimplemented!("prologue for {:?}", arch),
         }
@@ -725,24 +751,14 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
 
     fn epilogue(generated_asm: &mut String, arch: InlineAsmArch) {
         match arch {
-            InlineAsmArch::X86 => {
-                generated_asm.push_str("    pop ebp\n");
-                generated_asm.push_str("    ret\n");
-            }
             InlineAsmArch::X86_64 => {
+                generated_asm.push_str("    pop rbx\n");
                 generated_asm.push_str("    pop rbp\n");
                 generated_asm.push_str("    ret\n");
             }
-            InlineAsmArch::RiscV32 => {
-                generated_asm.push_str("    lw s0, 0(sp)\n");
-                generated_asm.push_str("    lw ra, 4(sp)\n");
-                generated_asm.push_str("    addi sp, sp, 8\n");
-                generated_asm.push_str("    ret\n");
-            }
-            InlineAsmArch::RiscV64 => {
-                generated_asm.push_str("    ld s0, 0(sp)\n");
-                generated_asm.push_str("    ld ra, 8(sp)\n");
-                generated_asm.push_str("    addi sp, sp, 16\n");
+            InlineAsmArch::AArch64 => {
+                generated_asm.push_str("    ldr x19, [sp, #24]\n");
+                generated_asm.push_str("    ldp fp, lr, [sp], #32\n");
                 generated_asm.push_str("    ret\n");
             }
             _ => unimplemented!("epilogue for {:?}", arch),
@@ -751,11 +767,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
 
     fn epilogue_noreturn(generated_asm: &mut String, arch: InlineAsmArch) {
         match arch {
-            InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
+            InlineAsmArch::X86_64 => {
                 generated_asm.push_str("    ud2\n");
             }
-            InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
-                generated_asm.push_str("    ebreak\n");
+            InlineAsmArch::AArch64 => {
+                generated_asm.push_str("    brk     #0x1");
             }
             _ => unimplemented!("epilogue_noreturn for {:?}", arch),
         }
@@ -768,25 +784,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
         offset: Size,
     ) {
         match arch {
-            InlineAsmArch::X86 => {
-                write!(generated_asm, "    mov [ebp+0x{:x}], ", offset.bytes()).unwrap();
-                reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap();
-                generated_asm.push('\n');
-            }
             InlineAsmArch::X86_64 => {
-                write!(generated_asm, "    mov [rbp+0x{:x}], ", offset.bytes()).unwrap();
+                write!(generated_asm, "    mov [rbx+0x{:x}], ", offset.bytes()).unwrap();
                 reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
                 generated_asm.push('\n');
             }
-            InlineAsmArch::RiscV32 => {
-                generated_asm.push_str("    sw ");
-                reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap();
-                writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
-            }
-            InlineAsmArch::RiscV64 => {
-                generated_asm.push_str("    sd ");
-                reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
-                writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
+            InlineAsmArch::AArch64 => {
+                generated_asm.push_str("    str ");
+                reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap();
+                writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
             }
             _ => unimplemented!("save_register for {:?}", arch),
         }
@@ -799,25 +805,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
         offset: Size,
     ) {
         match arch {
-            InlineAsmArch::X86 => {
-                generated_asm.push_str("    mov ");
-                reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap();
-                writeln!(generated_asm, ", [ebp+0x{:x}]", offset.bytes()).unwrap();
-            }
             InlineAsmArch::X86_64 => {
                 generated_asm.push_str("    mov ");
                 reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
-                writeln!(generated_asm, ", [rbp+0x{:x}]", offset.bytes()).unwrap();
-            }
-            InlineAsmArch::RiscV32 => {
-                generated_asm.push_str("    lw ");
-                reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap();
-                writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
+                writeln!(generated_asm, ", [rbx+0x{:x}]", offset.bytes()).unwrap();
             }
-            InlineAsmArch::RiscV64 => {
-                generated_asm.push_str("    ld ");
-                reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
-                writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
+            InlineAsmArch::AArch64 => {
+                generated_asm.push_str("    ldr ");
+                reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap();
+                writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
             }
             _ => unimplemented!("restore_register for {:?}", arch),
         }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index 63b5402f2b6..c1694760998 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -1,10 +1,10 @@
 //! Emulate LLVM intrinsics
 
+use rustc_middle::ty::GenericArgsRef;
+
 use crate::intrinsics::*;
 use crate::prelude::*;
 
-use rustc_middle::ty::GenericArgsRef;
-
 pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
index c20a9915930..0c211a06dc4 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
@@ -1,10 +1,10 @@
 //! Emulate AArch64 LLVM intrinsics
 
+use rustc_middle::ty::GenericArgsRef;
+
 use crate::intrinsics::*;
 use crate::prelude::*;
 
-use rustc_middle::ty::GenericArgsRef;
-
 pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
@@ -156,6 +156,41 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
             });
         }
 
+        // FIXME generalize vector types
+        "llvm.aarch64.neon.tbl1.v16i8" => {
+            intrinsic_args!(fx, args => (t, idx); intrinsic);
+
+            let zero = fx.bcx.ins().iconst(types::I8, 0);
+            for i in 0..16 {
+                let idx_lane = idx.value_lane(fx, i).load_scalar(fx);
+                let is_zero =
+                    fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, idx_lane, 16);
+                let t_idx = fx.bcx.ins().uextend(fx.pointer_type, idx_lane);
+                let t_lane = t.value_lane_dyn(fx, t_idx).load_scalar(fx);
+                let res = fx.bcx.ins().select(is_zero, zero, t_lane);
+                ret.place_lane(fx, i).to_ptr().store(fx, res, MemFlags::trusted());
+            }
+        }
+
+        // FIXME generalize vector types
+        "llvm.aarch64.neon.umaxp.v16i8" => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+
+            // FIXME add helper for horizontal pairwise operations
+            for i in 0..8 {
+                let lane1 = a.value_lane(fx, i * 2).load_scalar(fx);
+                let lane2 = a.value_lane(fx, i * 2 + 1).load_scalar(fx);
+                let res = fx.bcx.ins().umax(lane1, lane2);
+                ret.place_lane(fx, i).to_ptr().store(fx, res, MemFlags::trusted());
+            }
+            for i in 0..8 {
+                let lane1 = b.value_lane(fx, i * 2).load_scalar(fx);
+                let lane2 = b.value_lane(fx, i * 2 + 1).load_scalar(fx);
+                let res = fx.bcx.ins().umax(lane1, lane2);
+                ret.place_lane(fx, 8 + i).to_ptr().store(fx, res, MemFlags::trusted());
+            }
+        }
+
         /*
         _ if intrinsic.starts_with("llvm.aarch64.neon.sshl.v")
             || intrinsic.starts_with("llvm.aarch64.neon.sqshl.v")
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index e62de6b6147..0c9a94e1c23 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -1,10 +1,10 @@
 //! Emulate x86 LLVM intrinsics
 
+use rustc_middle::ty::GenericArgsRef;
+
 use crate::intrinsics::*;
 use crate::prelude::*;
 
-use rustc_middle::ty::GenericArgsRef;
-
 pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
@@ -74,8 +74,10 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             };
             let x = codegen_operand(fx, x);
             let y = codegen_operand(fx, y);
-            let kind = crate::constant::mir_operand_get_const_val(fx, kind)
-                .expect("llvm.x86.sse2.cmp.* kind not const");
+            let kind = match kind {
+                Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0,
+                Operand::Copy(_) | Operand::Move(_) => unreachable!("{kind:?}"),
+            };
 
             let flt_cc = match kind
                 .try_to_bits(Size::from_bytes(1))
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 36e9ba9c7f8..e94091e6a25 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -18,17 +18,16 @@ mod llvm_aarch64;
 mod llvm_x86;
 mod simd;
 
-pub(crate) use cpuid::codegen_cpuid_call;
-pub(crate) use llvm::codegen_llvm_intrinsic_call;
-
+use cranelift_codegen::ir::AtomicRmwOp;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
 
+pub(crate) use self::cpuid::codegen_cpuid_call;
+pub(crate) use self::llvm::codegen_llvm_intrinsic_call;
 use crate::prelude::*;
-use cranelift_codegen::ir::AtomicRmwOp;
 
 fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! {
     bug!("wrong number of args for intrinsic {}", intrinsic);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 6efbe149863..ea137c4ca1e 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -148,7 +148,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             let total_len = lane_count * 2;
 
             let indexes =
-                idx.iter().map(|idx| idx.unwrap_leaf().try_to_u16().unwrap()).collect::<Vec<u16>>();
+                idx.iter().map(|idx| idx.unwrap_leaf().try_to_u32().unwrap()).collect::<Vec<u32>>();
 
             for &idx in &indexes {
                 assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
@@ -216,8 +216,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 
             let indexes = {
                 use rustc_middle::mir::interpret::*;
-                let idx_const = crate::constant::mir_operand_get_const_val(fx, idx)
-                    .expect("simd_shuffle idx not const");
+                let idx_const = match idx {
+                    Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0,
+                    Operand::Copy(_) | Operand::Move(_) => unreachable!("{idx:?}"),
+                };
 
                 let idx_bytes = match idx_const {
                     ConstValue::Indirect { alloc_id, offset } => {
@@ -343,7 +345,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, ret_lane);
         }
 
-        sym::simd_neg => {
+        sym::simd_neg
+        | sym::simd_bswap
+        | sym::simd_bitreverse
+        | sym::simd_ctlz
+        | sym::simd_cttz => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
             if !a.layout().ty.is_simd() {
@@ -351,16 +357,21 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 return;
             }
 
-            simd_for_each_lane(
-                fx,
-                a,
-                ret,
-                &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() {
-                    ty::Int(_) => fx.bcx.ins().ineg(lane),
-                    ty::Float(_) => fx.bcx.ins().fneg(lane),
-                    _ => unreachable!(),
-                },
-            );
+            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| match (
+                lane_ty.kind(),
+                intrinsic,
+            ) {
+                (ty::Int(_), sym::simd_neg) => fx.bcx.ins().ineg(lane),
+                (ty::Float(_), sym::simd_neg) => fx.bcx.ins().fneg(lane),
+
+                (ty::Uint(ty::UintTy::U8) | ty::Int(ty::IntTy::I8), sym::simd_bswap) => lane,
+                (ty::Uint(_) | ty::Int(_), sym::simd_bswap) => fx.bcx.ins().bswap(lane),
+                (ty::Uint(_) | ty::Int(_), sym::simd_bitreverse) => fx.bcx.ins().bitrev(lane),
+                (ty::Uint(_) | ty::Int(_), sym::simd_ctlz) => fx.bcx.ins().clz(lane),
+                (ty::Uint(_) | ty::Int(_), sym::simd_cttz) => fx.bcx.ins().ctz(lane),
+
+                _ => unreachable!(),
+            });
         }
 
         sym::simd_add
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index d01ded8abaa..522fe7e425b 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -29,6 +29,8 @@ use std::any::Any;
 use std::cell::{Cell, RefCell};
 use std::sync::Arc;
 
+use cranelift_codegen::isa::TargetIsa;
+use cranelift_codegen::settings::{self, Configurable};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_data_structures::profiling::SelfProfilerRef;
@@ -39,9 +41,6 @@ use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
 use rustc_span::Symbol;
 
-use cranelift_codegen::isa::TargetIsa;
-use cranelift_codegen::settings::{self, Configurable};
-
 pub use crate::config::*;
 use crate::prelude::*;
 
@@ -76,22 +75,6 @@ mod value_and_place;
 mod vtable;
 
 mod prelude {
-    pub(crate) use rustc_span::{FileNameDisplayPreference, Span};
-
-    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-    pub(crate) use rustc_middle::bug;
-    pub(crate) use rustc_middle::mir::{self, *};
-    pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
-    pub(crate) use rustc_middle::ty::{
-        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
-        TypeFoldable, TypeVisitableExt, UintTy,
-    };
-    pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};
-
-    pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-
-    pub(crate) use rustc_index::Idx;
-
     pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
     pub(crate) use cranelift_codegen::ir::function::Function;
     pub(crate) use cranelift_codegen::ir::types;
@@ -103,6 +86,18 @@ mod prelude {
     pub(crate) use cranelift_codegen::Context;
     pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
     pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module};
+    pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+    pub(crate) use rustc_index::Idx;
+    pub(crate) use rustc_middle::bug;
+    pub(crate) use rustc_middle::mir::{self, *};
+    pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
+    pub(crate) use rustc_middle::ty::{
+        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
+        TypeFoldable, TypeVisitableExt, UintTy,
+    };
+    pub(crate) use rustc_span::{FileNameDisplayPreference, Span};
+    pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};
 
     pub(crate) use crate::abi::*;
     pub(crate) use crate::base::{codegen_operand, codegen_place};
@@ -263,9 +258,9 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
     let preserve_frame_pointer = sess.target.options.frame_pointer
         != rustc_target::spec::FramePointer::MayOmit
         || matches!(sess.opts.cg.force_frame_pointers, Some(true));
-    if preserve_frame_pointer {
-        flags_builder.set("preserve_frame_pointers", "true").unwrap();
-    }
+    flags_builder
+        .set("preserve_frame_pointers", if preserve_frame_pointer { "true" } else { "false" })
+        .unwrap();
 
     let tls_model = match target_triple.binary_format {
         BinaryFormat::Elf => "elf_gd",
diff --git a/compiler/rustc_codegen_cranelift/src/pointer.rs b/compiler/rustc_codegen_cranelift/src/pointer.rs
index b60e56720ed..11ac6b94678 100644
--- a/compiler/rustc_codegen_cranelift/src/pointer.rs
+++ b/compiler/rustc_codegen_cranelift/src/pointer.rs
@@ -1,11 +1,10 @@
 //! Defines [`Pointer`] which is used to improve the quality of the generated clif ir for pointer
 //! operations.
 
-use crate::prelude::*;
-
+use cranelift_codegen::ir::immediates::Offset32;
 use rustc_target::abi::Align;
 
-use cranelift_codegen::ir::immediates::Offset32;
+use crate::prelude::*;
 
 /// A pointer pointing either to a certain address, a certain stack slot or nothing.
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 0ead50c34ea..da84e54a916 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -63,8 +63,8 @@ use cranelift_codegen::{
     ir::entities::AnyEntity,
     write::{FuncWriter, PlainWriter},
 };
-
 use rustc_middle::ty::layout::FnAbiOf;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::config::{OutputFilenames, OutputType};
 
 use crate::prelude::*;
@@ -80,15 +80,17 @@ impl CommentWriter {
     pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
         let enabled = should_write_ir(tcx);
         let global_comments = if enabled {
-            vec![
-                format!("symbol {}", tcx.symbol_name(instance).name),
-                format!("instance {:?}", instance),
-                format!(
-                    "abi {:?}",
-                    RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())
-                ),
-                String::new(),
-            ]
+            with_no_trimmed_paths!({
+                vec![
+                    format!("symbol {}", tcx.symbol_name(instance).name),
+                    format!("instance {:?}", instance),
+                    format!(
+                        "abi {:?}",
+                        RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())
+                    ),
+                    String::new(),
+                ]
+            })
         } else {
             vec![]
         };
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 45893a4f3ac..3a6a6c9e3f5 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -1,11 +1,10 @@
 //! Definition of [`CValue`] and [`CPlace`]
 
-use crate::prelude::*;
-
-use rustc_middle::ty::FnSig;
-
 use cranelift_codegen::entity::EntityRef;
 use cranelift_codegen::ir::immediates::Offset32;
+use rustc_middle::ty::FnSig;
+
+use crate::prelude::*;
 
 fn codegen_field<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
@@ -310,7 +309,8 @@ impl<'tcx> CValue<'tcx> {
                 fx.bcx.ins().iconcat(lsb, msb)
             }
             ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Ref(..) | ty::RawPtr(..) => {
-                fx.bcx.ins().iconst(clif_ty, const_val.to_bits(layout.size).unwrap() as i64)
+                let raw_val = const_val.size().truncate(const_val.to_bits(layout.size).unwrap());
+                fx.bcx.ins().iconst(clif_ty, raw_val as i64)
             }
             ty::Float(FloatTy::F32) => {
                 fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap()))
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
index d2b7724a221..f075c744e45 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
@@ -57,8 +57,8 @@ jobs:
       uses: dawidd6/action-download-artifact@v2
       with:
           workflow: main.yml
-          name: ${{ matrix.libgccjit_version.gcc }}
-          path: gcc-build
+          name: gcc-13
+          path: gcc-13
           repo: antoyo/gcc
           branch: ${{ matrix.libgccjit_version.artifacts_branch }}
           event: push
@@ -71,9 +71,8 @@ jobs:
     - name: Setup path to libgccjit
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       run: |
-          echo $(readlink -f gcc-build) > gcc_path
-          # NOTE: the filename is still libgccjit.so even when the artifact name is different.
-          ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0
+          sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb
+          echo /usr/lib/ > gcc_path
 
     - name: Set env
       run: |
@@ -119,8 +118,8 @@ jobs:
 
     - name: Build
       run: |
-        ./prepare_build.sh
-        ${{ matrix.libgccjit_version.env_extra }} ./build.sh ${{ matrix.libgccjit_version.extra }}
+        ./y.sh prepare --only-libcore
+        ${{ matrix.libgccjit_version.env_extra }} ./y.sh build ${{ matrix.libgccjit_version.extra }}
         ${{ matrix.libgccjit_version.env_extra }} cargo test ${{ matrix.libgccjit_version.extra }}
         ./clean_all.sh
 
@@ -128,7 +127,7 @@ jobs:
       run: |
         git config --global user.email "user@example.com"
         git config --global user.name "User"
-        ./prepare.sh
+        ./y.sh prepare
 
     # Compile is a separate step, as the actions-rs/cargo action supports error annotations
     - name: Compile
@@ -141,6 +140,9 @@ jobs:
       if: ${{ matrix.libgccjit_version.gcc == 'libgccjit12.so' }}
       run: cat failing-ui-tests12.txt >> failing-ui-tests.txt
 
+    - name: Add more failing tests because the sysroot is not compiled with LTO
+      run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt
+
     - name: Run tests
       run: |
         ${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} ${{ matrix.libgccjit_version.extra }}
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
index c4e99469bc2..bd0415040e7 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
@@ -18,8 +18,6 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        libgccjit_version:
-          - { gcc: "libgccjit.so", artifacts_branch: "master" }
         commands: [
           "--test-successful-rustc --nb-parts 2 --current-part 0",
           "--test-successful-rustc --nb-parts 2 --current-part 1",
@@ -40,18 +38,17 @@ jobs:
       uses: dawidd6/action-download-artifact@v2
       with:
           workflow: main.yml
-          name: ${{ matrix.libgccjit_version.gcc }}
-          path: gcc-build
+          name: gcc-13
+          path: gcc-13
           repo: antoyo/gcc
-          branch: ${{ matrix.libgccjit_version.artifacts_branch }}
+          branch: "master"
           event: push
           search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts.
 
     - name: Setup path to libgccjit
       run: |
-          echo $(readlink -f gcc-build) > gcc_path
-          # NOTE: the filename is still libgccjit.so even when the artifact name is different.
-          ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0
+          sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb
+          echo /usr/lib/ > gcc_path
 
     - name: Set env
       run: |
@@ -88,8 +85,8 @@ jobs:
 
     - name: Build
       run: |
-        ./prepare_build.sh
-        ./build.sh --release --release-sysroot
+        ./y.sh prepare --only-libcore
+        EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot
         cargo test
         ./clean_all.sh
 
@@ -97,7 +94,9 @@ jobs:
       run: |
         git config --global user.email "user@example.com"
         git config --global user.name "User"
-        ./prepare.sh
+        ./y.sh prepare
+        # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros.
+        echo -n 'lto = "fat"' >> build_sysroot/Cargo.toml
 
     # Compile is a separate step, as the actions-rs/cargo action supports error annotations
     - name: Compile
@@ -106,6 +105,9 @@ jobs:
         command: build
         args: --release
 
+    - name: Add more failing tests because of undefined symbol errors (FIXME)
+      run: cat failing-lto-tests.txt >> failing-ui-tests.txt
+
     - name: Run tests
       run: |
-        ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }}
+        EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }}
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml
index 556c6444833..6c28326823c 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml
@@ -18,8 +18,6 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        libgccjit_version:
-          - { gcc: "libgccjit.so", artifacts_branch: "master" }
         cargo_runner: [
           "sde -future -rtm_mode full --",
           "",
@@ -54,18 +52,17 @@ jobs:
       uses: dawidd6/action-download-artifact@v2
       with:
           workflow: main.yml
-          name: ${{ matrix.libgccjit_version.gcc }}
-          path: gcc-build
+          name: gcc-13
+          path: gcc-13
           repo: antoyo/gcc
-          branch: ${{ matrix.libgccjit_version.artifacts_branch }}
+          branch: "master"
           event: push
           search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts.
 
     - name: Setup path to libgccjit
       run: |
-          echo $(readlink -f gcc-build) > gcc_path
-          # NOTE: the filename is still libgccjit.so even when the artifact name is different.
-          ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0
+          sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb
+          echo /usr/lib/ > gcc_path
 
     - name: Set env
       run: |
@@ -102,8 +99,8 @@ jobs:
 
     - name: Build
       run: |
-        ./prepare_build.sh
-        ./build.sh --release --release-sysroot
+        ./y.sh prepare --only-libcore
+        ./y.sh build --release --release-sysroot
         cargo test
 
     - name: Clean
@@ -115,7 +112,7 @@ jobs:
       run: |
         git config --global user.email "user@example.com"
         git config --global user.name "User"
-        ./prepare.sh
+        ./y.sh prepare
 
     # Compile is a separate step, as the actions-rs/cargo action supports error annotations
     - name: Compile
@@ -133,10 +130,11 @@ jobs:
       if: ${{ !matrix.cargo_runner }}
       run: |
         cd build_sysroot/sysroot_src/library/stdarch/
-        CHANNEL=release TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test
+        CHANNEL=release TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../cargo.sh test
 
     - name: Run stdarch tests
       if: ${{ matrix.cargo_runner }}
       run: |
         cd build_sysroot/sysroot_src/library/stdarch/
-        STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a
+        # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro.
+        STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a
diff --git a/compiler/rustc_codegen_gcc/.gitignore b/compiler/rustc_codegen_gcc/.gitignore
index c5ed7de200c..b44d1aa78c2 100644
--- a/compiler/rustc_codegen_gcc/.gitignore
+++ b/compiler/rustc_codegen_gcc/.gitignore
@@ -25,3 +25,4 @@ tools/llvmint
 tools/llvmint-2
 # The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics.
 llvm
+build_system/target
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index 1c8754bf675..85675fc40c3 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "aho-corasick"
-version = "0.7.18"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
 dependencies = [
  "memchr",
 ]
@@ -18,12 +18,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
+name = "bitflags"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+
+[[package]]
+name = "cc"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+
+[[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "errno"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+
+[[package]]
 name = "fm"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -35,7 +74,7 @@ dependencies = [
 [[package]]
 name = "gccjit"
 version = "1.0.0"
-source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984"
+source = "git+https://github.com/antoyo/gccjit.rs#0b158c68bf7e46732869d90550a98e886dee8858"
 dependencies = [
  "gccjit_sys",
 ]
@@ -43,7 +82,7 @@ dependencies = [
 [[package]]
 name = "gccjit_sys"
 version = "0.0.1"
-source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984"
+source = "git+https://github.com/antoyo/gccjit.rs#0b158c68bf7e46732869d90550a98e886dee8858"
 dependencies = [
  "libc",
 ]
@@ -58,24 +97,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "getrandom"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
 name = "hermit-abi"
-version = "0.1.19"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
+checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
 
 [[package]]
 name = "lang_tester"
@@ -95,86 +120,55 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.112"
+version = "0.2.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
 
 [[package]]
-name = "memchr"
-version = "2.4.1"
+name = "linux-raw-sys"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
 
 [[package]]
-name = "num_cpus"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.15"
+name = "memchr"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
-name = "rand"
-version = "0.8.4"
+name = "num_cpus"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
+ "hermit-abi",
  "libc",
- "rand_chacha",
- "rand_core",
- "rand_hc",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
 ]
 
 [[package]]
-name = "rand_hc"
-version = "0.3.1"
+name = "object"
+version = "0.30.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
 dependencies = [
- "rand_core",
+ "memchr",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.10"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
 ]
 
 [[package]]
 name = "regex"
-version = "1.5.4"
+version = "1.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -183,18 +177,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
-
-[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
+checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
 
 [[package]]
 name = "rustc_codegen_gcc"
@@ -202,11 +187,25 @@ version = "0.1.0"
 dependencies = [
  "gccjit",
  "lang_tester",
+ "object",
  "smallvec",
  "tempfile",
 ]
 
 [[package]]
+name = "rustix"
+version = "0.38.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
+dependencies = [
+ "bitflags 2.4.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
 name = "same-file"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -223,23 +222,22 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
 
 [[package]]
 name = "tempfile"
-version = "3.2.0"
+version = "3.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
 dependencies = [
  "cfg-if",
- "libc",
- "rand",
+ "fastrand",
  "redox_syscall",
- "remove_dir_all",
- "winapi",
+ "rustix",
+ "windows-sys",
 ]
 
 [[package]]
 name = "termcolor"
-version = "1.1.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
 dependencies = [
  "winapi-util",
 ]
@@ -255,9 +253,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-width"
-version = "0.1.9"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
 [[package]]
 name = "wait-timeout"
@@ -270,22 +268,15 @@ dependencies = [
 
 [[package]]
 name = "walkdir"
-version = "2.3.2"
+version = "2.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
 dependencies = [
  "same-file",
- "winapi",
  "winapi-util",
 ]
 
 [[package]]
-name = "wasi"
-version = "0.10.2+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
-
-[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -315,3 +306,69 @@ name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
index 81066d9ce1f..51fab147aa2 100644
--- a/compiler/rustc_codegen_gcc/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -27,7 +27,13 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
 # Local copy.
 #gccjit = { path = "../gccjit.rs" }
 
+object = { version = "0.30.1", default-features = false, features = [
+    "std",
+    "read",
+] }
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+# TODO(antoyo): make tempfile optional.
+tempfile = "3.7.1"
 
 [dev-dependencies]
 lang_tester = "0.3.9"
diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md
index a93637d9038..f001c83b08d 100644
--- a/compiler/rustc_codegen_gcc/Readme.md
+++ b/compiler/rustc_codegen_gcc/Readme.md
@@ -1,6 +1,7 @@
 # WIP libgccjit codegen backend for rust
 
 [![Chat on IRC](https://img.shields.io/badge/irc.libera.chat-%23rustc__codegen__gcc-blue.svg)](https://web.libera.chat/#rustc_codegen_gcc)
+[![Chat on Matrix](https://img.shields.io/badge/matrix.org-%23rustc__codegen__gcc-blue.svg)](https://matrix.to/#/#rustc_codegen_gcc:matrix.org)
 
 This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used.
 
@@ -14,9 +15,7 @@ A secondary goal is to check if using the gcc backend will provide any run-time
 ## Building
 
 **This requires a patched libgccjit in order to work.
-The patches in [this repository](https://github.com/antoyo/libgccjit-patches) need to be applied.
-(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.)
-You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
+You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
 
 To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue):
 
@@ -66,8 +65,8 @@ $ export RUST_COMPILER_RT_ROOT="$PWD/llvm/compiler-rt"
 Then you can run commands like this:
 
 ```bash
-$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking
-$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./build.sh --release
+$ ./y.sh prepare # download and patch sysroot src and install hyperfine for benchmarking
+$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./y.sh build --release
 ```
 
 To run the tests:
@@ -78,22 +77,29 @@ $ ./test.sh --release
 
 ## Usage
 
-`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions.
+`$CG_GCCJIT_DIR` is the directory you cloned this repo into in the following instructions:
+
+```bash
+export CG_GCCJIT_DIR=[the full path to rustc_codegen_gcc]
+```
 
 ### Cargo
 
 ```bash
-$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run
+$ CHANNEL="release" $CG_GCCJIT_DIR/cargo.sh run
 ```
 
 If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely.
 
+To use LTO, you need to set the variable `FAT_LTO=1` and `EMBED_LTO_BITCODE=1` in addition to setting `lto = "fat"` in the `Cargo.toml`.
+Don't set `FAT_LTO` when compiling the sysroot, though: only set `EMBED_LTO_BITCODE=1`.
+
 ### Rustc
 
 > You should prefer using the Cargo method.
 
 ```bash
-$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs
+$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs
 ```
 
 ## Env vars
@@ -105,8 +111,18 @@ $ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$c
     object files when their content should have been changed by a change to cg_gccjit.</dd>
     <dt>CG_GCCJIT_DISPLAY_CG_TIME</dt>
     <dd>Display the time it took to perform codegen for a crate</dd>
+    <dt>CG_RUSTFLAGS</dt>
+    <dd>Send additional flags to rustc. Can be used to build the sysroot without unwinding by setting `CG_RUSTFLAGS=-Cpanic=abort`.</dd>
+    <dt>CG_GCCJIT_DUMP_TO_FILE</dt>
+    <dd>Dump a C-like representation to /tmp/gccjit_dumps and enable debug info in order to debug this C-like representation.</dd>
 </dl>
 
+## Licensing
+
+While this crate is licensed under a dual Apache/MIT license, it links to `libgccjit` which is under the GPLv3+ and thus, the resulting toolchain (rustc + GCC codegen) will need to be released under the GPL license.
+
+However, programs compiled with `rustc_codegen_gcc` do not need to be released under a GPL license.
+
 ## Debugging
 
 Sometimes, libgccjit will crash and output an error like this:
@@ -182,6 +198,61 @@ set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc
 
 TODO(antoyo): but that's not what I remember I was doing.
 
+### `failed to build archive` error
+
+When you get this error:
+
+```
+error: failed to build archive: failed to open object file: No such file or directory (os error 2)
+```
+
+That can be caused by the fact that you try to compile with `lto = "fat"`, but you didn't compile the sysroot with LTO.
+(Not sure if that's the reason since I cannot reproduce anymore. Maybe it happened when forgetting setting `FAT_LTO`.)
+
+### ld: cannot find crtbegin.o
+
+When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors:
+
+```
+ld: cannot find crtbegin.o: No such file or directory
+ld: cannot find -lgcc: No such file or directory
+ld: cannot find -lgcc: No such file or directory
+libgccjit.so: error: error invoking gcc driver
+```
+
+To fix this, set the variables to `gcc-build/build/gcc`.
+
+### How to debug GCC LTO
+
+Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger.
+
+### How to send arguments to the GCC linker
+
+```
+CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../cargo.sh build
+```
+
+### How to see the personality functions in the asm dump
+
+```
+CG_RUSTFLAGS="-Clink-arg=-save-temps -v -Clink-arg=-dA" ../cargo.sh build
+```
+
+### How to see the LLVM IR for a sysroot crate
+
+```
+cargo build -v --target x86_64-unknown-linux-gnu -Zbuild-std
+# Take the command from the output and add --emit=llvm-ir
+```
+
+### To prevent the linker from unmangling symbols
+
+Run with:
+
+```
+COLLECT_NO_DEMANGLE=1
+```
+
 ### How to use a custom-build rustc
 
  * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`).
@@ -223,6 +294,11 @@ https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.2
 
 `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`.
 
+### How to generate GIMPLE
+
+If you need to check what gccjit is generating (GIMPLE), then take a look at how to
+generate it in [gimple.md](./doc/gimple.md).
+
 ### How to build a cross-compiling libgccjit
 
 #### Building libgccjit
@@ -239,4 +315,4 @@ https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.2
  * Set `linker='-Clinker=m68k-linux-gcc'`.
  * Set the path to the cross-compiling libgccjit in `gcc_path`.
  * Comment the line: `context.add_command_line_option("-masm=intel");` in src/base.rs.
- * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?).
+ * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?): Remove dylib from build_sysroot/sysroot_src/library/std/Cargo.toml.
diff --git a/compiler/rustc_codegen_gcc/build.sh b/compiler/rustc_codegen_gcc/build.sh
deleted file mode 100755
index ba0d0d04948..00000000000
--- a/compiler/rustc_codegen_gcc/build.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env bash
-
-#set -x
-set -e
-
-codegen_channel=debug
-sysroot_channel=debug
-
-flags=
-
-while [[ $# -gt 0 ]]; do
-    case $1 in
-        --release)
-            codegen_channel=release
-            shift
-            ;;
-        --release-sysroot)
-            sysroot_channel=release
-            shift
-            ;;
-        --no-default-features)
-            flags="$flags --no-default-features"
-            shift
-            ;;
-        --features)
-            shift
-            flags="$flags --features $1"
-            shift
-            ;;
-        *)
-            echo "Unknown option $1"
-            exit 1
-            ;;
-    esac
-done
-
-if [ -f ./gcc_path ]; then
-    export GCC_PATH=$(cat gcc_path)
-else
-    echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
-    exit 1
-fi
-
-export LD_LIBRARY_PATH="$GCC_PATH"
-export LIBRARY_PATH="$GCC_PATH"
-
-if [[ "$codegen_channel" == "release" ]]; then
-    export CHANNEL='release'
-    CARGO_INCREMENTAL=1 cargo rustc --release $flags
-else
-    echo $LD_LIBRARY_PATH
-    export CHANNEL='debug'
-    cargo rustc $flags
-fi
-
-source config.sh
-
-rm -r target/out || true
-mkdir -p target/out/gccjit
-
-echo "[BUILD] sysroot"
-if [[ "$sysroot_channel" == "release" ]]; then
-    time ./build_sysroot/build_sysroot.sh --release
-else
-    time ./build_sysroot/build_sysroot.sh
-fi
-
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml
index a84f86a8218..e5658273c97 100644
--- a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml
@@ -2,6 +2,7 @@
 authors = ["bjorn3 <bjorn3@users.noreply.github.com>"]
 name = "sysroot"
 version = "0.0.0"
+resolver = "2"
 
 [dependencies]
 core = { path = "./sysroot_src/library/core" }
@@ -18,3 +19,4 @@ rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-st
 
 [profile.release]
 debug = true
+#lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed.
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
index 9d692d599f6..851e9895ce2 100755
--- a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
+++ b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
@@ -5,9 +5,9 @@
 set -e
 cd $(dirname "$0")
 
-pushd ../ >/dev/null
+pushd ../
 source ./config.sh
-popd >/dev/null
+popd
 
 # Cleanup for previous run
 #     v Clean target dir except for build scripts and incremental cache
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
deleted file mode 100755
index 71b3876bac2..00000000000
--- a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env bash
-set -e
-cd $(dirname "$0")
-
-SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/"
-DST_DIR="sysroot_src"
-
-if [ ! -e $SRC_DIR ]; then
-    echo "Please install rust-src component"
-    exit 1
-fi
-
-rm -rf $DST_DIR
-mkdir -p $DST_DIR/library
-cp -r $SRC_DIR/library $DST_DIR/
-
-pushd $DST_DIR
-echo "[GIT] init"
-git init
-echo "[GIT] add"
-git add .
-echo "[GIT] commit"
-
-# This is needed on systems where nothing is configured.
-# git really needs something here, or it will fail.
-# Even using --author is not enough.
-git config user.email || git config user.email "none@example.com"
-git config user.name || git config user.name "None"
-
-git commit -m "Initial commit" -q
-for file in $(ls ../../patches/ | grep -v patcha); do
-    echo "[GIT] apply" $file
-    git apply ../../patches/$file
-    git add -A
-    git commit --no-gpg-sign -m "Patch $file"
-done
-popd
-
-echo "Successfully prepared libcore for building"
diff --git a/compiler/rustc_codegen_gcc/build_system/Cargo.lock b/compiler/rustc_codegen_gcc/build_system/Cargo.lock
new file mode 100644
index 00000000000..86268e19160
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "y"
+version = "0.1.0"
diff --git a/compiler/rustc_codegen_gcc/build_system/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/Cargo.toml
new file mode 100644
index 00000000000..f36709ea036
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "y"
+version = "0.1.0"
+edition = "2021"
+
+[[bin]]
+name = "y"
+path = "src/main.rs"
diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs
new file mode 100644
index 00000000000..e2819c37ad9
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs
@@ -0,0 +1,233 @@
+use crate::config::set_config;
+use crate::utils::{
+    get_gcc_path, run_command, run_command_with_env, run_command_with_output_and_env, walk_dir,
+};
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::fs;
+use std::path::Path;
+
+#[derive(Default)]
+struct BuildArg {
+    codegen_release_channel: bool,
+    sysroot_release_channel: bool,
+    features: Vec<String>,
+    gcc_path: String,
+}
+
+impl BuildArg {
+    fn new() -> Result<Option<Self>, String> {
+        let gcc_path = get_gcc_path()?;
+        let mut build_arg = Self {
+            gcc_path,
+            ..Default::default()
+        };
+        // We skip binary name and the `build` command.
+        let mut args = std::env::args().skip(2);
+
+        while let Some(arg) = args.next() {
+            match arg.as_str() {
+                "--release" => build_arg.codegen_release_channel = true,
+                "--release-sysroot" => build_arg.sysroot_release_channel = true,
+                "--no-default-features" => {
+                    build_arg.features.push("--no-default-features".to_string());
+                }
+                "--features" => {
+                    if let Some(arg) = args.next() {
+                        build_arg.features.push("--features".to_string());
+                        build_arg.features.push(arg.as_str().into());
+                    } else {
+                        return Err(
+                            "Expected a value after `--features`, found nothing".to_string()
+                        );
+                    }
+                }
+                "--help" => {
+                    Self::usage();
+                    return Ok(None);
+                }
+                arg => return Err(format!("Unknown argument `{}`", arg)),
+            }
+        }
+        Ok(Some(build_arg))
+    }
+
+    fn usage() {
+        println!(
+            r#"
+`build` command help:
+
+    --release              : Build codegen in release mode
+    --release-sysroot      : Build sysroot in release mode
+    --no-default-features  : Add `--no-default-features` flag
+    --features [arg]       : Add a new feature [arg]
+    --help                 : Show this help
+"#
+        )
+    }
+}
+
+fn build_sysroot(
+    env: &mut HashMap<String, String>,
+    release_mode: bool,
+    target_triple: &str,
+) -> Result<(), String> {
+    std::env::set_current_dir("build_sysroot")
+        .map_err(|error| format!("Failed to go to `build_sysroot` directory: {:?}", error))?;
+    // Cleanup for previous run
+    // Clean target dir except for build scripts and incremental cache
+    let _ = walk_dir(
+        "target",
+        |dir: &Path| {
+            for top in &["debug", "release"] {
+                let _ = fs::remove_dir_all(dir.join(top).join("build"));
+                let _ = fs::remove_dir_all(dir.join(top).join("deps"));
+                let _ = fs::remove_dir_all(dir.join(top).join("examples"));
+                let _ = fs::remove_dir_all(dir.join(top).join("native"));
+
+                let _ = walk_dir(
+                    dir.join(top),
+                    |sub_dir: &Path| {
+                        if sub_dir
+                            .file_name()
+                            .map(|filename| filename.to_str().unwrap().starts_with("libsysroot"))
+                            .unwrap_or(false)
+                        {
+                            let _ = fs::remove_dir_all(sub_dir);
+                        }
+                        Ok(())
+                    },
+                    |file: &Path| {
+                        if file
+                            .file_name()
+                            .map(|filename| filename.to_str().unwrap().starts_with("libsysroot"))
+                            .unwrap_or(false)
+                        {
+                            let _ = fs::remove_file(file);
+                        }
+                        Ok(())
+                    },
+                );
+            }
+            Ok(())
+        },
+        |_| Ok(()),
+    );
+
+    let _ = fs::remove_file("Cargo.lock");
+    let _ = fs::remove_file("test_target/Cargo.lock");
+    let _ = fs::remove_dir_all("sysroot");
+
+    // Builds libs
+    let channel = if release_mode {
+        let rustflags = env
+            .get("RUSTFLAGS")
+            .cloned()
+            .unwrap_or_default();
+        env.insert(
+            "RUSTFLAGS".to_string(),
+            format!("{} -Zmir-opt-level=3", rustflags),
+        );
+        run_command_with_output_and_env(
+            &[
+                &"cargo",
+                &"build",
+                &"--target",
+                &target_triple,
+                &"--release",
+            ],
+            None,
+            Some(&env),
+        )?;
+        "release"
+    } else {
+        run_command_with_output_and_env(
+            &[
+                &"cargo",
+                &"build",
+                &"--target",
+                &target_triple,
+                &"--features",
+                &"compiler_builtins/c",
+            ],
+            None,
+            Some(env),
+        )?;
+        "debug"
+    };
+
+    // Copy files to sysroot
+    let sysroot_path = format!("sysroot/lib/rustlib/{}/lib/", target_triple);
+    fs::create_dir_all(&sysroot_path)
+        .map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_path, error))?;
+    let copier = |dir_to_copy: &Path| {
+        run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
+    };
+    walk_dir(
+        &format!("target/{}/{}/deps", target_triple, channel),
+        copier,
+        copier,
+    )?;
+
+    Ok(())
+}
+
+fn build_codegen(args: &BuildArg) -> Result<(), String> {
+    let mut env = HashMap::new();
+
+    let current_dir =
+        std::env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
+    if let Ok(rt_root) = std::env::var("RUST_COMPILER_RT_ROOT") {
+        env.insert("RUST_COMPILER_RT_ROOT".to_string(), rt_root);
+    } else {
+        env.insert(
+            "RUST_COMPILER_RT_ROOT".to_string(),
+            format!("{}", current_dir.join("llvm/compiler-rt").display()),
+        );
+    }
+    env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone());
+    env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone());
+
+    let mut command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"rustc"];
+    if args.codegen_release_channel {
+        command.push(&"--release");
+        env.insert("CHANNEL".to_string(), "release".to_string());
+        env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string());
+    } else {
+        env.insert("CHANNEL".to_string(), "debug".to_string());
+    }
+    let ref_features = args.features.iter().map(|s| s.as_str()).collect::<Vec<_>>();
+    for feature in &ref_features {
+        command.push(feature);
+    }
+    run_command_with_env(&command, None, Some(&env))?;
+
+    let config = set_config(&mut env, &[], Some(&args.gcc_path))?;
+
+    // We voluntarily ignore the error.
+    let _ = fs::remove_dir_all("target/out");
+    let gccjit_target = "target/out/gccjit";
+    fs::create_dir_all(gccjit_target).map_err(|error| {
+        format!(
+            "Failed to create directory `{}`: {:?}",
+            gccjit_target, error
+        )
+    })?;
+
+    println!("[BUILD] sysroot");
+    build_sysroot(
+        &mut env,
+        args.sysroot_release_channel,
+        &config.target_triple,
+    )?;
+    Ok(())
+}
+
+pub fn run() -> Result<(), String> {
+    let args = match BuildArg::new()? {
+        Some(args) => args,
+        None => return Ok(()),
+    };
+    build_codegen(&args)?;
+    Ok(())
+}
diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs
new file mode 100644
index 00000000000..4f2e33f0f99
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs
@@ -0,0 +1,125 @@
+use crate::utils::{get_gcc_path, get_os_name, get_rustc_host_triple};
+use std::collections::HashMap;
+use std::env as std_env;
+
+pub struct ConfigInfo {
+    pub target_triple: String,
+    pub rustc_command: Vec<String>,
+    pub run_wrapper: Option<&'static str>,
+}
+
+// Returns the beginning for the command line of rustc.
+pub fn set_config(
+    env: &mut HashMap<String, String>,
+    test_flags: &[String],
+    gcc_path: Option<&str>,
+) -> Result<ConfigInfo, String> {
+    env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());
+
+    let gcc_path = match gcc_path {
+        Some(path) => path.to_string(),
+        None => get_gcc_path()?,
+    };
+    env.insert("GCC_PATH".to_string(), gcc_path.clone());
+
+    let os_name = get_os_name()?;
+    let dylib_ext = match os_name.as_str() {
+        "Linux" => "so",
+        "Darwin" => "dylib",
+        os => return Err(format!("unsupported OS `{}`", os)),
+    };
+    let host_triple = get_rustc_host_triple()?;
+    let mut linker = None;
+    let mut target_triple = host_triple.as_str();
+    let mut run_wrapper = None;
+    // FIXME: handle this with a command line flag?
+    // let mut target_triple = "m68k-unknown-linux-gnu";
+
+    if host_triple != target_triple {
+        if target_triple == "m68k-unknown-linux-gnu" {
+            target_triple = "mips-unknown-linux-gnu";
+            linker = Some("-Clinker=m68k-linux-gcc");
+        } else if target_triple == "aarch64-unknown-linux-gnu" {
+            // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+            linker = Some("-Clinker=aarch64-linux-gnu-gcc");
+            run_wrapper = Some("qemu-aarch64 -L /usr/aarch64-linux-gnu");
+        } else {
+            return Err(format!("unknown non-native platform `{}`", target_triple));
+        }
+    }
+    let current_dir =
+        std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
+    let channel = if let Some(channel) = env.get("CHANNEL") {
+        channel.as_str()
+    } else {
+        "debug"
+    };
+    let cg_backend_path = current_dir
+        .join("target")
+        .join(channel)
+        .join(&format!("librustc_codegen_gcc.{}", dylib_ext));
+    let sysroot_path = current_dir.join("build_sysroot/sysroot");
+    let mut rustflags = Vec::new();
+    if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
+        rustflags.push(cg_rustflags.clone());
+    }
+    if let Some(linker) = linker {
+        rustflags.push(linker.to_string());
+    }
+    rustflags.extend_from_slice(&[
+        "-Csymbol-mangling-version=v0".to_string(),
+        "-Cdebuginfo=2".to_string(),
+        format!("-Zcodegen-backend={}", cg_backend_path.display()),
+        "--sysroot".to_string(),
+        sysroot_path.display().to_string(),
+    ]);
+
+    // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO.
+    // TODO(antoyo): remove when we can handle ThinLTO.
+    if !env.contains_key(&"FAT_LTO".to_string()) {
+        rustflags.push("-Clto=off".to_string());
+    }
+    rustflags.extend_from_slice(test_flags);
+    // FIXME(antoyo): remove once the atomic shim is gone
+    if os_name == "Darwin" {
+        rustflags.extend_from_slice(&[
+            "-Clink-arg=-undefined".to_string(),
+            "-Clink-arg=dynamic_lookup".to_string(),
+        ]);
+    }
+    env.insert("RUSTFLAGS".to_string(), rustflags.join(" "));
+    // display metadata load errors
+    env.insert("RUSTC_LOG".to_string(), "warn".to_string());
+
+    let sysroot = current_dir.join(&format!(
+        "build_sysroot/sysroot/lib/rustlib/{}/lib",
+        target_triple
+    ));
+    let ld_library_path = format!(
+        "{target}:{sysroot}:{gcc_path}",
+        target = current_dir.join("target/out").display(),
+        sysroot = sysroot.display(),
+    );
+    env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone());
+    env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path);
+
+    // NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc.
+    // To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH.
+    // Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc
+    let path = std::env::var("PATH").unwrap_or_default();
+    env.insert("PATH".to_string(), format!("/opt/gcc/bin:{}", path));
+
+    let mut rustc_command = vec!["rustc".to_string()];
+    rustc_command.extend_from_slice(&rustflags);
+    rustc_command.extend_from_slice(&[
+        "-L".to_string(),
+        "crate=target/out".to_string(),
+        "--out-dir".to_string(),
+        "target/out".to_string(),
+    ]);
+    Ok(ConfigInfo {
+        target_triple: target_triple.to_string(),
+        rustc_command,
+        run_wrapper,
+    })
+}
diff --git a/compiler/rustc_codegen_gcc/build_system/src/main.rs b/compiler/rustc_codegen_gcc/build_system/src/main.rs
new file mode 100644
index 00000000000..332a14ff0a2
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/main.rs
@@ -0,0 +1,62 @@
+use std::env;
+use std::process;
+
+mod build;
+mod config;
+mod prepare;
+mod rustc_info;
+mod utils;
+
+macro_rules! arg_error {
+    ($($err:tt)*) => {{
+        eprintln!($($err)*);
+        eprintln!();
+        usage();
+        std::process::exit(1);
+    }};
+}
+
+fn usage() {
+    println!(
+        "\
+Available commands for build_system:
+
+    prepare  : Run prepare command
+    build    : Run build command
+    --help   : Show this message"
+    );
+}
+
+pub enum Command {
+    Prepare,
+    Build,
+}
+
+fn main() {
+    if env::var("RUST_BACKTRACE").is_err() {
+        env::set_var("RUST_BACKTRACE", "1");
+    }
+
+    let command = match env::args().nth(1).as_deref() {
+        Some("prepare") => Command::Prepare,
+        Some("build") => Command::Build,
+        Some("--help") => {
+            usage();
+            process::exit(0);
+        }
+        Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
+        Some(command) => arg_error!("Unknown command {}", command),
+        None => {
+            usage();
+            process::exit(0);
+        }
+    };
+
+    if let Err(e) = match command {
+        Command::Prepare => prepare::run(),
+        Command::Build => build::run(),
+    } {
+        eprintln!("Command failed to run: {e:?}");
+        process::exit(1);
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/build_system/src/prepare.rs b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs
new file mode 100644
index 00000000000..b258ddf3664
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs
@@ -0,0 +1,227 @@
+use crate::rustc_info::get_rustc_path;
+use crate::utils::{cargo_install, git_clone, run_command, run_command_with_output, walk_dir};
+
+use std::fs;
+use std::path::Path;
+
+fn prepare_libcore(sysroot_path: &Path) -> Result<(), String> {
+    let rustc_path = match get_rustc_path() {
+        Some(path) => path,
+        None => return Err("`rustc` path not found".to_string()),
+    };
+
+    let parent = match rustc_path.parent() {
+        Some(path) => path,
+        None => return Err(format!("No parent for `{}`", rustc_path.display())),
+    };
+
+    let rustlib_dir = parent
+        .join("../lib/rustlib/src/rust")
+        .canonicalize()
+        .map_err(|error| format!("Failed to canonicalize path: {:?}", error))?;
+    if !rustlib_dir.is_dir() {
+        return Err("Please install `rust-src` component".to_string());
+    }
+
+    let sysroot_dir = sysroot_path.join("sysroot_src");
+    if sysroot_dir.is_dir() {
+        if let Err(error) = fs::remove_dir_all(&sysroot_dir) {
+            return Err(format!(
+                "Failed to remove `{}`: {:?}",
+                sysroot_dir.display(),
+                error,
+            ));
+        }
+    }
+
+    let sysroot_library_dir = sysroot_dir.join("library");
+    fs::create_dir_all(&sysroot_library_dir).map_err(|error| {
+        format!(
+            "Failed to create folder `{}`: {:?}",
+            sysroot_library_dir.display(),
+            error,
+        )
+    })?;
+
+    run_command(
+        &[&"cp", &"-r", &rustlib_dir.join("library"), &sysroot_dir],
+        None,
+    )?;
+
+    println!("[GIT] init (cwd): `{}`", sysroot_dir.display());
+    run_command(&[&"git", &"init"], Some(&sysroot_dir))?;
+    println!("[GIT] add (cwd): `{}`", sysroot_dir.display());
+    run_command(&[&"git", &"add", &"."], Some(&sysroot_dir))?;
+    println!("[GIT] commit (cwd): `{}`", sysroot_dir.display());
+
+    // This is needed on systems where nothing is configured.
+    // git really needs something here, or it will fail.
+    // Even using --author is not enough.
+    run_command(
+        &[&"git", &"config", &"user.email", &"none@example.com"],
+        Some(&sysroot_dir),
+    )?;
+    run_command(
+        &[&"git", &"config", &"user.name", &"None"],
+        Some(&sysroot_dir),
+    )?;
+    run_command(
+        &[&"git", &"config", &"core.autocrlf", &"false"],
+        Some(&sysroot_dir),
+    )?;
+    run_command(
+        &[&"git", &"config", &"commit.gpgSign", &"false"],
+        Some(&sysroot_dir),
+    )?;
+    run_command(
+        &[&"git", &"commit", &"-m", &"Initial commit", &"-q"],
+        Some(&sysroot_dir),
+    )?;
+
+    let mut patches = Vec::new();
+    walk_dir(
+        "patches",
+        |_| Ok(()),
+        |file_path: &Path| {
+            patches.push(file_path.to_path_buf());
+            Ok(())
+        },
+    )?;
+    patches.sort();
+    for file_path in patches {
+        println!("[GIT] apply `{}`", file_path.display());
+        let path = Path::new("../..").join(file_path);
+        run_command_with_output(&[&"git", &"apply", &path], Some(&sysroot_dir))?;
+        run_command_with_output(&[&"git", &"add", &"-A"], Some(&sysroot_dir))?;
+        run_command_with_output(
+            &[
+                &"git",
+                &"commit",
+                &"--no-gpg-sign",
+                &"-m",
+                &format!("Patch {}", path.display()),
+            ],
+            Some(&sysroot_dir),
+        )?;
+    }
+    println!("Successfully prepared libcore for building");
+    Ok(())
+}
+
+// build with cg_llvm for perf comparison
+fn build_raytracer(repo_dir: &Path) -> Result<(), String> {
+    run_command(&[&"cargo", &"build"], Some(repo_dir))?;
+    let mv_target = repo_dir.join("raytracer_cg_llvm");
+    if mv_target.is_file() {
+        std::fs::remove_file(&mv_target)
+            .map_err(|e| format!("Failed to remove file `{}`: {e:?}", mv_target.display()))?;
+    }
+    run_command(
+        &[&"mv", &"target/debug/main", &"raytracer_cg_llvm"],
+        Some(repo_dir),
+    )?;
+    Ok(())
+}
+
+fn clone_and_setup<F>(repo_url: &str, checkout_commit: &str, extra: Option<F>) -> Result<(), String>
+where
+    F: Fn(&Path) -> Result<(), String>,
+{
+    let clone_result = git_clone(repo_url, None)?;
+    if !clone_result.ran_clone {
+        println!("`{}` has already been cloned", clone_result.repo_name);
+    }
+    let repo_path = Path::new(&clone_result.repo_name);
+    run_command(&[&"git", &"checkout", &"--", &"."], Some(&repo_path))?;
+    run_command(&[&"git", &"checkout", &checkout_commit], Some(&repo_path))?;
+    let filter = format!("-{}-", clone_result.repo_name);
+    walk_dir(
+        "crate_patches",
+        |_| Ok(()),
+        |file_path| {
+            let patch = file_path.as_os_str().to_str().unwrap();
+            if patch.contains(&filter) && patch.ends_with(".patch") {
+                run_command_with_output(
+                    &[&"git", &"am", &file_path.canonicalize().unwrap()],
+                    Some(&repo_path),
+                )?;
+            }
+            Ok(())
+        },
+    )?;
+    if let Some(extra) = extra {
+        extra(&repo_path)?;
+    }
+    Ok(())
+}
+
+struct PrepareArg {
+    only_libcore: bool,
+}
+
+impl PrepareArg {
+    fn new() -> Result<Option<Self>, String> {
+        let mut only_libcore = false;
+
+        for arg in std::env::args().skip(2) {
+            match arg.as_str() {
+                "--only-libcore" => only_libcore = true,
+                "--help" => {
+                    Self::usage();
+                    return Ok(None);
+                }
+                a => return Err(format!("Unknown argument `{a}`")),
+            }
+        }
+        Ok(Some(Self { only_libcore }))
+    }
+
+    fn usage() {
+        println!(
+            r#"
+`prepare` command help:
+
+    --only-libcore  : Only setup libcore and don't clone other repositories
+    --help          : Show this help
+"#
+        )
+    }
+}
+
+pub fn run() -> Result<(), String> {
+    let args = match PrepareArg::new()? {
+        Some(a) => a,
+        None => return Ok(()),
+    };
+    let sysroot_path = Path::new("build_sysroot");
+    prepare_libcore(sysroot_path)?;
+
+    if !args.only_libcore {
+        cargo_install("hyperfine")?;
+
+        let to_clone = &[
+            (
+                "https://github.com/rust-random/rand.git",
+                "0f933f9c7176e53b2a3c7952ded484e1783f0bf1",
+                None,
+            ),
+            (
+                "https://github.com/rust-lang/regex.git",
+                "341f207c1071f7290e3f228c710817c280c8dca1",
+                None,
+            ),
+            (
+                "https://github.com/ebobby/simple-raytracer",
+                "804a7a21b9e673a482797aa289a18ed480e4d813",
+                Some(build_raytracer),
+            ),
+        ];
+
+        for (repo_url, checkout_commit, cb) in to_clone {
+            clone_and_setup(repo_url, checkout_commit, *cb)?;
+        }
+    }
+
+    println!("Successfully ran `prepare`");
+    Ok(())
+}
diff --git a/compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs b/compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs
new file mode 100644
index 00000000000..0988b56d81e
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs
@@ -0,0 +1,12 @@
+use std::path::{Path, PathBuf};
+
+use crate::utils::run_command;
+
+pub fn get_rustc_path() -> Option<PathBuf> {
+    if let Ok(rustc) = std::env::var("RUSTC") {
+        return Some(PathBuf::from(rustc));
+    }
+    run_command(&[&"rustup", &"which", &"rustc"], None)
+        .ok()
+        .map(|out| Path::new(String::from_utf8(out.stdout).unwrap().trim()).to_path_buf())
+}
diff --git a/compiler/rustc_codegen_gcc/build_system/src/utils.rs b/compiler/rustc_codegen_gcc/build_system/src/utils.rs
new file mode 100644
index 00000000000..536f33a8029
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/utils.rs
@@ -0,0 +1,240 @@
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::fmt::Debug;
+use std::fs;
+use std::path::Path;
+use std::process::{Command, ExitStatus, Output};
+
+fn get_command_inner(
+    input: &[&dyn AsRef<OsStr>],
+    cwd: Option<&Path>,
+    env: Option<&HashMap<String, String>>,
+) -> Command {
+    let (cmd, args) = match input {
+        [] => panic!("empty command"),
+        [cmd, args @ ..] => (cmd, args),
+    };
+    let mut command = Command::new(cmd);
+    command.args(args);
+    if let Some(cwd) = cwd {
+        command.current_dir(cwd);
+    }
+    if let Some(env) = env {
+        command.envs(env.iter().map(|(k, v)| (k.as_str(), v.as_str())));
+    }
+    command
+}
+
+fn check_exit_status(
+    input: &[&dyn AsRef<OsStr>],
+    cwd: Option<&Path>,
+    exit_status: ExitStatus,
+) -> Result<(), String> {
+    if exit_status.success() {
+        Ok(())
+    } else {
+        Err(format!(
+            "Command `{}`{} exited with status {:?}",
+            input
+                .iter()
+                .map(|s| s.as_ref().to_str().unwrap())
+                .collect::<Vec<_>>()
+                .join(" "),
+            cwd.map(|cwd| format!(" (running in folder `{}`)", cwd.display()))
+                .unwrap_or_default(),
+            exit_status.code(),
+        ))
+    }
+}
+
+fn command_error<D: Debug>(input: &[&dyn AsRef<OsStr>], cwd: &Option<&Path>, error: D) -> String {
+    format!(
+        "Command `{}`{} failed to run: {error:?}",
+        input
+            .iter()
+            .map(|s| s.as_ref().to_str().unwrap())
+            .collect::<Vec<_>>()
+            .join(" "),
+        cwd.as_ref()
+            .map(|cwd| format!(" (running in folder `{}`)", cwd.display(),))
+            .unwrap_or_default(),
+    )
+}
+
+pub fn run_command(input: &[&dyn AsRef<OsStr>], cwd: Option<&Path>) -> Result<Output, String> {
+    run_command_with_env(input, cwd, None)
+}
+
+pub fn run_command_with_env(
+    input: &[&dyn AsRef<OsStr>],
+    cwd: Option<&Path>,
+    env: Option<&HashMap<String, String>>,
+) -> Result<Output, String> {
+    let output = get_command_inner(input, cwd, env)
+        .output()
+        .map_err(|e| command_error(input, &cwd, e))?;
+    check_exit_status(input, cwd, output.status)?;
+    Ok(output)
+}
+
+pub fn run_command_with_output(
+    input: &[&dyn AsRef<OsStr>],
+    cwd: Option<&Path>,
+) -> Result<(), String> {
+    let exit_status = get_command_inner(input, cwd, None)
+        .spawn()
+        .map_err(|e| command_error(input, &cwd, e))?
+        .wait()
+        .map_err(|e| command_error(input, &cwd, e))?;
+    check_exit_status(input, cwd, exit_status)?;
+    Ok(())
+}
+
+pub fn run_command_with_output_and_env(
+    input: &[&dyn AsRef<OsStr>],
+    cwd: Option<&Path>,
+    env: Option<&HashMap<String, String>>,
+) -> Result<(), String> {
+    let exit_status = get_command_inner(input, cwd, env)
+        .spawn()
+        .map_err(|e| command_error(input, &cwd, e))?
+        .wait()
+        .map_err(|e| command_error(input, &cwd, e))?;
+    check_exit_status(input, cwd, exit_status)?;
+    Ok(())
+}
+
+pub fn cargo_install(to_install: &str) -> Result<(), String> {
+    let output = run_command(&[&"cargo", &"install", &"--list"], None)?;
+
+    let to_install_needle = format!("{to_install} ");
+    // cargo install --list returns something like this:
+    //
+    // mdbook-toc v0.8.0:
+    //     mdbook-toc
+    // rust-reduce v0.1.0:
+    //     rust-reduce
+    //
+    // We are only interested into the command name so we only look for lines ending with `:`.
+    if String::from_utf8(output.stdout)
+        .unwrap()
+        .lines()
+        .any(|line| line.ends_with(':') && line.starts_with(&to_install_needle))
+    {
+        return Ok(());
+    }
+    // We voluntarily ignore this error.
+    if run_command_with_output(&[&"cargo", &"install", &to_install], None).is_err() {
+        println!("Skipping installation of `{to_install}`");
+    }
+    Ok(())
+}
+
+pub fn get_os_name() -> Result<String, String> {
+    let output = run_command(&[&"uname"], None)?;
+    let name = std::str::from_utf8(&output.stdout)
+        .unwrap_or("")
+        .trim()
+        .to_string();
+    if !name.is_empty() {
+        Ok(name)
+    } else {
+        Err("Failed to retrieve the OS name".to_string())
+    }
+}
+
+pub fn get_rustc_host_triple() -> Result<String, String> {
+    let output = run_command(&[&"rustc", &"-vV"], None)?;
+    let content = std::str::from_utf8(&output.stdout).unwrap_or("");
+
+    for line in content.split('\n').map(|line| line.trim()) {
+        if !line.starts_with("host:") {
+            continue;
+        }
+        return Ok(line.split(':').nth(1).unwrap().trim().to_string());
+    }
+    Err("Cannot find host triple".to_string())
+}
+
+pub fn get_gcc_path() -> Result<String, String> {
+    let content = match fs::read_to_string("gcc_path") {
+        Ok(content) => content,
+        Err(_) => {
+            return Err(
+                "Please put the path to your custom build of libgccjit in the file \
+                   `gcc_path`, see Readme.md for details"
+                    .into(),
+            )
+        }
+    };
+    match content
+        .split('\n')
+        .map(|line| line.trim())
+        .filter(|line| !line.is_empty())
+        .next()
+    {
+        Some(gcc_path) => {
+            let path = Path::new(gcc_path);
+            if !path.exists() {
+                Err(format!(
+                    "Path `{}` contained in the `gcc_path` file doesn't exist",
+                    gcc_path,
+                ))
+            } else {
+                Ok(gcc_path.into())
+            }
+        }
+        None => Err("No path found in `gcc_path` file".into()),
+    }
+}
+
+pub struct CloneResult {
+    pub ran_clone: bool,
+    pub repo_name: String,
+}
+
+pub fn git_clone(to_clone: &str, dest: Option<&Path>) -> Result<CloneResult, String> {
+    let repo_name = to_clone.split('/').last().unwrap();
+    let repo_name = match repo_name.strip_suffix(".git") {
+        Some(n) => n.to_string(),
+        None => repo_name.to_string(),
+    };
+
+    let dest = dest
+        .map(|dest| dest.join(&repo_name))
+        .unwrap_or_else(|| Path::new(&repo_name).into());
+    if dest.is_dir() {
+        return Ok(CloneResult {
+            ran_clone: false,
+            repo_name,
+        });
+    }
+
+    run_command_with_output(&[&"git", &"clone", &to_clone, &dest], None)?;
+    Ok(CloneResult {
+        ran_clone: true,
+        repo_name,
+    })
+}
+
+pub fn walk_dir<P, D, F>(dir: P, mut dir_cb: D, mut file_cb: F) -> Result<(), String>
+where
+    P: AsRef<Path>,
+    D: FnMut(&Path) -> Result<(), String>,
+    F: FnMut(&Path) -> Result<(), String>,
+{
+    let dir = dir.as_ref();
+    for entry in fs::read_dir(dir)
+        .map_err(|error| format!("Failed to read dir `{}`: {:?}", dir.display(), error))?
+    {
+        let entry = entry
+            .map_err(|error| format!("Failed to read entry in `{}`: {:?}", dir.display(), error))?;
+        let entry_path = entry.path();
+        if entry_path.is_dir() {
+            dir_cb(&entry_path)?;
+        } else {
+            file_cb(&entry_path)?;
+        }
+    }
+    Ok(())
+}
diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh
index 166e83901c4..c686df0c72a 100644
--- a/compiler/rustc_codegen_gcc/config.sh
+++ b/compiler/rustc_codegen_gcc/config.sh
@@ -38,10 +38,17 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
    fi
 fi
 
-export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS"
+# Since we don't support ThinLTO, disable LTO completely when not trying to do LTO.
+# TODO(antoyo): remove when we can handle ThinLTO.
+disable_lto_flags=''
+if [[ ! -v FAT_LTO ]]; then
+    disable_lto_flags='-Clto=off'
+fi
+
+export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS"
 
 # FIXME(antoyo): remove once the atomic shim is gone
-if [[ `uname` == 'Darwin' ]]; then
+if [[ unamestr == 'Darwin' ]]; then
    export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
 fi
 
@@ -50,3 +57,7 @@ export RUSTC_LOG=warn # display metadata load errors
 
 export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH"
 export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
+# NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc.
+# To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH.
+# Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc
+export PATH="/opt/gcc/bin:$PATH"
diff --git a/compiler/rustc_codegen_gcc/doc/add-attribute.md b/compiler/rustc_codegen_gcc/doc/add-attribute.md
new file mode 100644
index 00000000000..ae3bcc5e2eb
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/doc/add-attribute.md
@@ -0,0 +1,17 @@
+# Add support for a new function attribute
+
+To add support for a new function attribute in libgccjit, you need to do the following steps:
+
+ 1. Copy the corresponding function from `c-family/c-attribs.cc` into `jit/dummy-frontend.cc`. For example if you add the `target` attribute, the function name will be `handle_target_attribute`.
+ 2. Copy the corresponding entry from the `c_common_attribute_table` variable in the `c-family/c-attribs.cc` file into the `jit_attribute_table` variable in `jit/dummy-frontend.cc`.
+ 3. Add a new variant in the `gcc_jit_fn_attribute` enum in the `jit/libgccjit.h` file.
+ 4. Add a test to ensure the attribute is correctly applied in `gcc/testsuite/jit.dg/`. Take a look at `gcc/testsuite/jit.dg/test-nonnull.c` if you want an example.
+ 5. Run the example like this (in your `gcc-build` folder): `make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-nonnull.c"`
+
+Once done, you need to update the [gccjit.rs] crate to add the new enum variant in the corresponding enum (`FnAttribute`).
+
+Finally, you need to update this repository by calling the relevant API you added in [gccjit.rs].
+
+To test it, build `gcc`, run `cargo update -p gccjit` and then you can test the generated output for a given Rust crate.
+
+[gccjit.rs]: https://github.com/antoyo/gccjit.rs
diff --git a/compiler/rustc_codegen_gcc/doc/gimple.md b/compiler/rustc_codegen_gcc/doc/gimple.md
new file mode 100644
index 00000000000..145c4eda3c1
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/doc/gimple.md
@@ -0,0 +1,111 @@
+# GIMPLE
+
+You can see the full documentation about what GIMPLE is [here](https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html). In this document we will explain how to generate it.
+
+First, we'll copy the content from `gcc/gcc/testsuite/jit.dg/test-const-attribute.c` into a
+file named `local.c` and remove the content we're not interested into:
+
+```diff
+- /* { dg-do compile { target x86_64-*-* } } */
+...
+- /* We don't want set_options() in harness.h to set -O3 to see that the const
+-    attribute affects the optimizations. */
+- #define TEST_ESCHEWS_SET_OPTIONS
+- static void set_options (gcc_jit_context *ctxt, const char *argv0)
+- {
+-   // Set "-O3".
+-   gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
+- }
+-
+- #define TEST_COMPILING_TO_FILE
+- #define OUTPUT_KIND      GCC_JIT_OUTPUT_KIND_ASSEMBLER
+- #define OUTPUT_FILENAME  "output-of-test-const-attribute.c.s"
+- #include "harness.h"
+...
+- /* { dg-final { jit-verify-output-file-was-created "" } } */
+- /* Check that the loop was optimized away */
+- /* { dg-final { jit-verify-assembler-output-not "jne" } } */
+```
+
+Then we'll add a `main` function which will call the `create_code` function but
+also add the calls we need to generate the GIMPLE:
+
+```C
+int main() {
+    gcc_jit_context *ctxt = gcc_jit_context_acquire();
+    // To set `-O3`, update it depending on your needs.
+    gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
+    // Very important option to generate the gimple format.
+    gcc_jit_context_set_bool_option(ctxt, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
+    create_code(ctxt, NULL);
+
+    gcc_jit_context_compile(ctxt);
+    // If you want to compile to assembly (or any other format) directly, you can
+    // use the following call instead:
+    // gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_ASSEMBLER, "out.s");
+
+    return 0;
+}
+```
+
+Then we can compile it by using:
+
+```console
+gcc local.c -I `pwd`/gcc/gcc/jit/ -L `pwd`/gcc-build/gcc -lgccjit -o out
+```
+
+And finally when you run it:
+
+```console
+LD_LIBRARY_PATH=`pwd`/gcc-build/gcc LIBRARY_PATH=`pwd`/gcc-build/gcc ./out
+```
+
+It should display:
+
+```c
+__attribute__((const))
+int xxx ()
+{
+  int D.3394;
+  int sum;
+  int x;
+
+  <D.3377>:
+  x = 45;
+  sum = 0;
+  goto loop_cond;
+  loop_cond:
+  x = x >> 1;
+  if (x != 0) goto after_loop; else goto loop_body;
+  loop_body:
+  _1 = foo (x);
+  _2 = _1 * 2;
+  x = x + _2;
+  goto loop_cond;
+  after_loop:
+  D.3394 = sum;
+  return D.3394;
+}
+```
+
+An alternative way to generate the GIMPLE is to replace:
+
+```c
+    gcc_jit_context_set_bool_option(ctxt, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
+```
+
+with:
+
+```c
+    gcc_jit_context_add_command_line_option(ctxt, "-fdump-tree-gimple");
+```
+
+(although you can have both at the same time too). Then you can compile it like previously. Only one difference: before executing it, I recommend to run:
+
+```console
+rm -rf /tmp/libgccjit-*
+```
+
+to make it easier for you to know which folder to look into.
+
+Once the execution is done, you should now have a file with path looking like `/tmp/libgccjit-9OFqkD/fake.c.006t.gimple` which contains the GIMPLE format.
diff --git a/compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md b/compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md
new file mode 100644
index 00000000000..7a47ef29f3c
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md
@@ -0,0 +1,44 @@
+This guide explains what to do to send a GCC patch for review.
+
+All the commands are supposed to be run in the folder where you cloned GCC.
+
+```bash
+./contrib/gcc-changelog/git_check_commit.py
+```
+
+You can provide a specific commit hash:
+
+```bash
+./contrib/gcc-changelog/git_check_commit.py abdef78989
+```
+
+a range:
+
+```bash
+./contrib/gcc-changelog/git_check_commit.py HEAD~2
+```
+
+or even a comparison with a remote branch:
+
+```bash
+./contrib/gcc-changelog/git_check_commit.py upstream/master..HEAD
+```
+
+When there is no more errors, generate the git patch:
+
+```bash
+git format-patch -1 `git rev-parse --short HEAD`
+```
+
+Then you can run the remaining checks using:
+
+```bash
+contrib/check_GNU_style.sh 0001-your-patch.patch
+```
+
+When you have no more errors, you can send the `.patch` file to GCC by sending an
+email to `gcc-patches@gcc.gnu.org` and to the relevant GCC mailing lists
+depending on what your patch changes. You can find the list of the mailing lists
+[here](https://gcc.gnu.org/lists.html).
+
+You can find more information about "contributing to GCC" [here](https://gcc.gnu.org/contribute.html).
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
index 754e7931412..f1954a30cf8 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_example.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs
@@ -1,5 +1,6 @@
 #![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
 #![no_std]
+#![allow(internal_features)]
 
 extern crate alloc;
 extern crate alloc_system;
diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs
index 3deef419f42..56ff84e4bdf 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_system.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs
@@ -12,7 +12,7 @@
               target_arch = "mips",
               target_arch = "mips32r6",
               target_arch = "powerpc",
-              target_arch = "csky"
+              target_arch = "csky",
               target_arch = "powerpc64"))]
 const MIN_ALIGN: usize = 8;
 #[cfg(any(target_arch = "x86_64",
diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
index 3af0ba09e0b..b299aa87974 100644
--- a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -2,6 +2,7 @@
 
 #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
 #![feature(rustc_attrs)]
+#![allow(internal_features)]
 
 use std::{
     ops::{Deref, CoerceUnsized, DispatchFromDyn},
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index 0cd7e6047c2..34328520343 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -4,7 +4,7 @@
     thread_local
 )]
 #![no_core]
-#![allow(dead_code)]
+#![allow(dead_code, internal_features)]
 
 #[no_mangle]
 unsafe extern "C" fn _Unwind_Resume() {
@@ -429,6 +429,15 @@ fn panic_cannot_unwind() -> ! {
     }
 }
 
+#[lang = "panic_in_cleanup"]
+#[rustc_nounwind]
+fn panic_in_cleanup() -> ! {
+    unsafe {
+        libc::printf("panic in a destructor during cleanup\n\0" as *const str as *const i8);
+        intrinsics::abort();
+    }
+}
+
 #[lang = "panic_bounds_check"]
 #[track_caller]
 fn panic_bounds_check(index: usize, len: usize) -> ! {
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 b93d6859706..c3aea571815 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -5,7 +5,7 @@
     extern_types, thread_local
 )]
 #![no_core]
-#![allow(dead_code, non_camel_case_types)]
+#![allow(dead_code, internal_features, non_camel_case_types)]
 
 extern crate mini_core;
 
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
index 5e2e7f25a2c..c60bc7fb724 100644
--- a/compiler/rustc_codegen_gcc/example/mod_bench.rs
+++ b/compiler/rustc_codegen_gcc/example/mod_bench.rs
@@ -1,5 +1,6 @@
 #![feature(start, core_intrinsics, lang_items)]
 #![no_std]
+#![allow(internal_features)]
 
 #[link(name = "c")]
 extern {}
diff --git a/compiler/rustc_codegen_gcc/failing-lto-tests.txt b/compiler/rustc_codegen_gcc/failing-lto-tests.txt
new file mode 100644
index 00000000000..2e0b6134070
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/failing-lto-tests.txt
@@ -0,0 +1,23 @@
+tests/ui/lint/unsafe_code/forge_unsafe_block.rs
+tests/ui/lint/unused-qualification-in-derive-expansion.rs
+tests/ui/macro-quote-test.rs
+tests/ui/macros/proc_macro.rs
+tests/ui/panic-runtime/lto-unwind.rs
+tests/ui/resolve/derive-macro-1.rs
+tests/ui/resolve/derive-macro-2.rs
+tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-pretty.rs
+tests/ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs
+tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs
+tests/ui/rust-2018/suggestions-not-always-applicable.rs
+tests/ui/rust-2021/reserved-prefixes-via-macro.rs
+tests/ui/underscore-imports/duplicate.rs
+tests/ui/async-await/issues/issue-60674.rs
+tests/ui/attributes/main-removed-2/main.rs
+tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs
+tests/ui/crate-loading/cross-compiled-proc-macro.rs
+tests/ui/derives/derive-marker-tricky.rs
+tests/ui/diagnostic_namespace/existing_proc_macros.rs
+tests/ui/fmt/format-args-capture-issue-106408.rs
+tests/ui/fmt/indoc-issue-106408.rs
+tests/ui/hygiene/issue-77523-def-site-async-await.rs
+tests/ui/inherent-impls-overlap-check/no-overlap.rs
diff --git a/compiler/rustc_codegen_gcc/failing-non-lto-tests.txt b/compiler/rustc_codegen_gcc/failing-non-lto-tests.txt
new file mode 100644
index 00000000000..2f338f7d3c8
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/failing-non-lto-tests.txt
@@ -0,0 +1,11 @@
+tests/ui/issues/issue-44056.rs
+tests/ui/lto/fat-lto.rs
+tests/ui/lto/debuginfo-lto.rs
+tests/ui/lto/lto-many-codegen-units.rs
+tests/ui/lto/issue-100772.rs
+tests/ui/lto/lto-rustc-loads-linker-plugin.rs
+tests/ui/panic-runtime/lto-unwind.rs
+tests/ui/sanitize/issue-111184-generator-witness.rs
+tests/ui/sepcomp/sepcomp-lib-lto.rs
+tests/ui/lto/lto-opt-level-s.rs
+tests/ui/lto/lto-opt-level-z.rs
diff --git a/compiler/rustc_codegen_gcc/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/failing-ui-tests.txt
index 801464daae9..ed56a11a170 100644
--- a/compiler/rustc_codegen_gcc/failing-ui-tests.txt
+++ b/compiler/rustc_codegen_gcc/failing-ui-tests.txt
@@ -1,11 +1,5 @@
-tests/ui/allocator/custom-in-block.rs
-tests/ui/allocator/custom-in-submodule.rs
-tests/ui/allocator/custom.rs
-tests/ui/allocator/hygiene.rs
 tests/ui/allocator/no_std-alloc-error-handler-custom.rs
 tests/ui/allocator/no_std-alloc-error-handler-default.rs
-tests/ui/allocator/xcrate-use.rs
-tests/ui/allocator/xcrate-use2.rs
 tests/ui/asm/may_unwind.rs
 tests/ui/asm/x86_64/multiple-clobber-abi.rs
 tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs
@@ -14,15 +8,12 @@ tests/ui/linkage-attr/linkage1.rs
 tests/ui/lto/dylib-works.rs
 tests/ui/numbers-arithmetic/saturating-float-casts.rs
 tests/ui/polymorphization/promoted-function.rs
-tests/ui/process/nofile-limit.rs
 tests/ui/sepcomp/sepcomp-cci.rs
 tests/ui/sepcomp/sepcomp-extern.rs
 tests/ui/sepcomp/sepcomp-fns-backwards.rs
 tests/ui/sepcomp/sepcomp-fns.rs
 tests/ui/sepcomp/sepcomp-statics.rs
 tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
-tests/ui/sse2.rs
-tests/ui/target-feature/missing-plusminus.rs
 tests/ui/asm/x86_64/may_unwind.rs
 tests/ui/backtrace.rs
 tests/ui/catch-unwind-bang.rs
@@ -54,8 +45,8 @@ tests/ui/issues/issue-40883.rs
 tests/ui/issues/issue-43853.rs
 tests/ui/issues/issue-47364.rs
 tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
-tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
 tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs
+tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
 tests/ui/simd/issue-17170.rs
 tests/ui/simd/issue-39720.rs
 tests/ui/simd/issue-89193.rs
@@ -65,6 +56,18 @@ tests/ui/alloc-error/default-alloc-error-hook.rs
 tests/ui/generator/panic-safe.rs
 tests/ui/issues/issue-14875.rs
 tests/ui/issues/issue-29948.rs
-tests/ui/panic-while-printing.rs
-tests/ui/enum-discriminant/get_discr.rs
 tests/ui/panics/nested_panic_caught.rs
+tests/ui/simd/intrinsic/generic-bswap-byte.rs
+tests/ui/const_prop/ice-issue-111353.rs
+tests/ui/process/println-with-broken-pipe.rs
+tests/ui/panic-runtime/lto-abort.rs
+tests/ui/lto/thin-lto-inlines2.rs
+tests/ui/lto/weak-works.rs
+tests/ui/lto/thin-lto-inlines.rs
+tests/ui/lto/thin-lto-global-allocator.rs
+tests/ui/lto/msvc-imp-present.rs
+tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
+tests/ui/lto/all-crates.rs
+tests/ui/async-await/deep-futures-are-freeze.rs
+tests/ui/closures/capture-unsized-by-ref.rs
+tests/ui/generator/resume-after-return.rs
diff --git a/compiler/rustc_codegen_gcc/failing-ui-tests12.txt b/compiler/rustc_codegen_gcc/failing-ui-tests12.txt
index 8c27bd8b8ca..0ac0a034af4 100644
--- a/compiler/rustc_codegen_gcc/failing-ui-tests12.txt
+++ b/compiler/rustc_codegen_gcc/failing-ui-tests12.txt
@@ -37,3 +37,4 @@ tests/ui/simd/intrinsic/generic-gather-pass.rs
 tests/ui/simd/issue-85915-simd-ptrs.rs
 tests/ui/issues/issue-68010-large-zst-consts.rs
 tests/ui/rust-2018/proc-macro-crate-in-paths.rs
+tests/ui/target-feature/missing-plusminus.rs
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl
index 2fd0daee3e7..5ca0a2e1b6d 100644
--- a/compiler/rustc_codegen_gcc/messages.ftl
+++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -1,3 +1,7 @@
+codegen_gcc_unknown_ctarget_feature_prefix =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = features must begin with a `+` to enable or `-` to disable it
+
 codegen_gcc_invalid_minimum_alignment =
     invalid minimum global alignment: {$err}
 
@@ -9,3 +13,29 @@ codegen_gcc_tied_target_features = the target features {$features} must all be e
 
 codegen_gcc_unwinding_inline_asm =
     GCC backend does not support unwinding from inline asm
+
+codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err}
+
+codegen_gcc_dynamic_linking_with_lto =
+    cannot prefer dynamic linking when performing LTO
+    .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
+
+codegen_gcc_load_bitcode = failed to load bitcode of module "{$name}"
+
+codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs
+
+codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
+
+codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
+
+codegen_gcc_unknown_ctarget_feature =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = it is still passed through to the codegen backend
+    .possible_feature = you might have meant: `{$rust_feature}`
+    .consider_filing_feature_request = consider filing a feature request
+
+codegen_gcc_missing_features =
+    add the missing features in a `target_feature` attribute
+
+codegen_gcc_target_feature_disable_or_enable =
+    the target features {$features} must all be either enabled or disabled together
diff --git a/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch b/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch
index 93c63b5dcac..2a55f2cb796 100644
--- a/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch
+++ b/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch
@@ -1,25 +1,26 @@
-From c3821e02fbd6cb5ad6e06d759fccdc9073712375 Mon Sep 17 00:00:00 2001
+From b8f3eed3053c9333b5dfbeaeb2a6a65a4b3156df Mon Sep 17 00:00:00 2001
 From: Antoni Boucher <bouanto@zoho.com>
-Date: Tue, 7 Jun 2022 21:40:13 -0400
-Subject: [PATCH] Add stdarch Cargo.toml for testing
+Date: Tue, 29 Aug 2023 13:06:34 -0400
+Subject: [PATCH] Patch 0001-Add-stdarch-Cargo.toml-for-testing.patch
 
 ---
- library/stdarch/Cargo.toml | 20 ++++++++++++++++++++
- 1 file changed, 20 insertions(+)
+ library/stdarch/Cargo.toml | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
  create mode 100644 library/stdarch/Cargo.toml
 
 diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml
 new file mode 100644
-index 0000000..fbe0a95
+index 0000000..4c63700
 --- /dev/null
 +++ b/library/stdarch/Cargo.toml
-@@ -0,0 +1,20 @@
+@@ -0,0 +1,21 @@
 +[workspace]
++resolver = "1"
 +members = [
 +  "crates/core_arch",
 +  "crates/std_detect",
 +  "crates/stdarch-gen",
-+  "examples/"
++  #"examples/"
 +]
 +exclude = [
 +  "crates/wasm-assert-instr-tests"
@@ -35,5 +36,5 @@ index 0000000..fbe0a95
 +opt-level = 3
 +incremental = true
 -- 
-2.26.2.7.g19db9cfb68.dirty
+2.42.0
 
diff --git a/compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch b/compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch
deleted file mode 100644
index 1b71df1ca8d..00000000000
--- a/compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From a2d53a324a02c04b76c0e9d39dc15cd443a3b8b2 Mon Sep 17 00:00:00 2001
-From: Antoni Boucher <bouanto@zoho.com>
-Date: Fri, 25 Nov 2022 11:18:11 -0500
-Subject: [PATCH] Disable examples
-
----
- library/stdarch/Cargo.toml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml
-index fbe0a95..748d72d 100644
---- a/library/stdarch/Cargo.toml
-+++ b/library/stdarch/Cargo.toml
-@@ -3,7 +3,7 @@ members = [
-   "crates/core_arch",
-   "crates/std_detect",
-   "crates/stdarch-gen",
--  "examples/"
-+  #"examples/"
- ]
- exclude = [
-   "crates/wasm-assert-instr-tests"
--- 
-2.26.2.7.g19db9cfb68.dirty
-
diff --git a/compiler/rustc_codegen_gcc/prepare.sh b/compiler/rustc_codegen_gcc/prepare.sh
deleted file mode 100755
index e98f24c6e12..00000000000
--- a/compiler/rustc_codegen_gcc/prepare.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-set -e
-set -v
-
-source prepare_build.sh
-
-cargo install hyperfine || echo "Skipping hyperfine install"
-
-git clone https://github.com/rust-random/rand.git || echo "rust-random/rand has already been cloned"
-pushd rand
-git checkout -- .
-git checkout 0f933f9c7176e53b2a3c7952ded484e1783f0bf1
-git am ../crate_patches/*-rand-*.patch
-popd
-
-git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
-pushd regex
-git checkout -- .
-git checkout 341f207c1071f7290e3f228c710817c280c8dca1
-popd
-
-git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned"
-pushd simple-raytracer
-git checkout -- .
-git checkout 804a7a21b9e673a482797aa289a18ed480e4d813
-
-# build with cg_llvm for perf comparison
-cargo build
-mv target/debug/main raytracer_cg_llvm
-popd
diff --git a/compiler/rustc_codegen_gcc/prepare_build.sh b/compiler/rustc_codegen_gcc/prepare_build.sh
deleted file mode 100755
index 8194360da4b..00000000000
--- a/compiler/rustc_codegen_gcc/prepare_build.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-set -e
-set -v
-
-./build_sysroot/prepare_sysroot_src.sh
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
index ebb04d0069c..25a1cea98cc 100644
--- a/compiler/rustc_codegen_gcc/rust-toolchain
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-06-19"
+channel = "nightly-2023-10-08"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh
index 041079bc9c6..a4f938e4b5b 100755
--- a/compiler/rustc_codegen_gcc/rustup.sh
+++ b/compiler/rustc_codegen_gcc/rustup.sh
@@ -16,7 +16,7 @@ case $1 in
         done
 
         ./clean_all.sh
-        ./prepare.sh
+        ./y.sh prepare
         ;;
     "commit")
         git add rust-toolchain
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index a49530ebb4c..35bb0b6e5f4 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -3,7 +3,9 @@ use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::ty::Ty;
-use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
+#[cfg(feature = "master")]
+use rustc_session::config;
+use rustc_target::abi::call::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind};
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
@@ -120,30 +122,50 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                 }
             };
 
+        #[cfg(feature = "master")]
+        let apply_attrs = |ty: Type<'gcc>, attrs: &ArgAttributes| {
+            if cx.sess().opts.optimize != config::OptLevel::No
+                && attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias)
+            {
+                ty.make_restrict()
+            } else {
+                ty
+            }
+        };
+        #[cfg(not(feature = "master"))]
+        let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes| {
+            ty
+        };
+
         for arg in self.args.iter() {
             let arg_ty = match arg.mode {
                 PassMode::Ignore => continue,
-                PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
-                PassMode::Pair(..) => {
-                    argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0));
-                    argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
+                PassMode::Pair(a, b) => {
+                    argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a));
+                    argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b));
                     continue;
                 }
-                PassMode::Indirect { meta_attrs: Some(_), .. } => {
-                    unimplemented!();
-                }
                 PassMode::Cast { ref cast, pad_i32 } => {
                     // add padding
                     if pad_i32 {
                         argument_tys.push(Reg::i32().gcc_type(cx));
                     }
-                    cast.gcc_type(cx)
+                    let ty = cast.gcc_type(cx);
+                    apply_attrs(ty, &cast.attrs)
                 }
-                PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => {
+                PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => {
+                    // This is a "byval" argument, so we don't apply the `restrict` attribute on it.
                     on_stack_param_indices.insert(argument_tys.len());
                     arg.memory_ty(cx)
                 },
-                PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
+                PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs),
+                PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
+                    apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs)
+                }
+                PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
+                    assert!(!on_stack);
+                    apply_attrs(apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs), &meta_attrs)
+                }
             };
             argument_tys.push(arg_ty);
         }
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index edd7ab722f6..c8c098e2973 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -1,6 +1,6 @@
 #[cfg(feature="master")]
 use gccjit::FnAttribute;
-use gccjit::{FunctionType, GlobalKind, ToRValue};
+use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
 use rustc_ast::expand::allocator::{
     alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
     ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
@@ -22,7 +22,6 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
         };
     let i8 = context.new_type::<i8>();
     let i8p = i8.make_pointer();
-    let void = context.new_type::<()>();
 
     if kind == AllocatorKind::Default {
         for method in ALLOCATOR_METHODS {
@@ -47,67 +46,62 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
                     panic!("invalid allocator output")
                 }
             };
-            let name = global_fn_name(method.name);
+            let from_name = global_fn_name(method.name);
+            let to_name = default_fn_name(method.name);
 
-            let args: Vec<_> = types.iter().enumerate()
-                .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
-                .collect();
-            let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
+            create_wrapper_function(tcx, context, &from_name, &to_name, &types, output);
+        }
+    }
 
-            if tcx.sess.target.options.default_hidden_visibility {
-                #[cfg(feature="master")]
-                func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
-            }
-            if tcx.sess.must_emit_unwind_tables() {
-                // TODO(antoyo): emit unwind tables.
-            }
+    // FIXME(bjorn3): Add noreturn attribute
+    create_wrapper_function(
+        tcx,
+        context,
+        "__rust_alloc_error_handler",
+        &alloc_error_handler_name(alloc_error_handler_kind),
+        &[usize, usize],
+        None,
+    );
 
-            let callee = default_fn_name(method.name);
-            let args: Vec<_> = types.iter().enumerate()
-                .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
-                .collect();
-            let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
-            #[cfg(feature="master")]
-            callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
-
-            let block = func.new_block("entry");
-
-            let args = args
-                .iter()
-                .enumerate()
-                .map(|(i, _)| func.get_param(i as i32).to_rvalue())
-                .collect::<Vec<_>>();
-            let ret = context.new_call(None, callee, &args);
-            //llvm::LLVMSetTailCall(ret, True);
-            if output.is_some() {
-                block.end_with_return(None, ret);
-            }
-            else {
-                block.end_with_void_return(None);
-            }
+    let name = OomStrategy::SYMBOL.to_string();
+    let global = context.new_global(None, GlobalKind::Exported, i8, name);
+    let value = tcx.sess.opts.unstable_opts.oom.should_panic();
+    let value = context.new_rvalue_from_int(i8, value as i32);
+    global.global_set_initializer_rvalue(value);
 
-            // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
-            // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
-        }
-    }
+    let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
+    let global = context.new_global(None, GlobalKind::Exported, i8, name);
+    let value = context.new_rvalue_from_int(i8, 0);
+    global.global_set_initializer_rvalue(value);
+}
+
+fn create_wrapper_function(
+    tcx: TyCtxt<'_>,
+    context: &Context<'_>,
+    from_name: &str,
+    to_name: &str,
+    types: &[Type<'_>],
+    output: Option<Type<'_>>,
+) {
+    let void = context.new_type::<()>();
 
-    let types = [usize, usize];
-    let name = "__rust_alloc_error_handler".to_string();
     let args: Vec<_> = types.iter().enumerate()
         .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
         .collect();
-    let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
+    let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, from_name, false);
 
-    if tcx.sess.target.default_hidden_visibility {
+    if tcx.sess.target.options.default_hidden_visibility {
         #[cfg(feature="master")]
         func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
     }
+    if tcx.sess.must_emit_unwind_tables() {
+        // TODO(antoyo): emit unwind tables.
+    }
 
-    let callee = alloc_error_handler_name(alloc_error_handler_kind);
     let args: Vec<_> = types.iter().enumerate()
         .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
         .collect();
-    let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false);
+    let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, to_name, false);
     #[cfg(feature="master")]
     callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
 
@@ -118,18 +112,15 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
         .enumerate()
         .map(|(i, _)| func.get_param(i as i32).to_rvalue())
         .collect::<Vec<_>>();
-    let _ret = context.new_call(None, callee, &args);
+    let ret = context.new_call(None, callee, &args);
     //llvm::LLVMSetTailCall(ret, True);
-    block.end_with_void_return(None);
-
-    let name = OomStrategy::SYMBOL.to_string();
-    let global = context.new_global(None, GlobalKind::Exported, i8, name);
-    let value = tcx.sess.opts.unstable_opts.oom.should_panic();
-    let value = context.new_rvalue_from_int(i8, value as i32);
-    global.global_set_initializer_rvalue(value);
+    if output.is_some() {
+        block.end_with_return(None, ret);
+    }
+    else {
+        block.end_with_void_return(None);
+    }
 
-    let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
-    let global = context.new_global(None, GlobalKind::Exported, i8, name);
-    let value = context.new_rvalue_from_int(i8, 0);
-    global.global_set_initializer_rvalue(value);
+    // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
+    // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
 }
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 905fdac92e9..f3a9ca77a67 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -452,10 +452,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         }
 
                         InlineAsmOperandRef::Const { ref string } => {
-                            // Const operands get injected directly into the template
-                            if att_dialect {
-                                template_str.push('$');
-                            }
                             template_str.push_str(string);
                         }
                     }
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index eb0cce19b85..971e019a4f6 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -4,72 +4,13 @@ use gccjit::Function;
 use rustc_attr::InstructionSetAttr;
 #[cfg(feature="master")]
 use rustc_attr::InlineAttr;
-use rustc_codegen_ssa::target_features::tied_target_features;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty;
 #[cfg(feature="master")]
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_session::Session;
 use rustc_span::symbol::sym;
-use smallvec::{smallvec, SmallVec};
 
 use crate::{context::CodegenCx, errors::TiedTargetFeatures};
-
-// Given a map from target_features to whether they are enabled or disabled,
-// ensure only valid combinations are allowed.
-pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> {
-    for tied in tied_target_features(sess) {
-        // Tied features must be set to the same value, or not set at all
-        let mut tied_iter = tied.iter();
-        let enabled = features.get(tied_iter.next().unwrap());
-        if tied_iter.any(|feature| enabled != features.get(feature)) {
-            return Some(tied);
-        }
-    }
-    None
-}
-
-// TODO(antoyo): maybe move to a new module gcc_util.
-// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
-    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
-    match (arch, s) {
-        ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
-        ("x86", "pclmulqdq") => smallvec!["pclmul"],
-        ("x86", "rdrand") => smallvec!["rdrnd"],
-        ("x86", "bmi1") => smallvec!["bmi"],
-        ("x86", "cmpxchg16b") => smallvec!["cx16"],
-        ("x86", "avx512vaes") => smallvec!["vaes"],
-        ("x86", "avx512gfni") => smallvec!["gfni"],
-        ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
-        // NOTE: seems like GCC requires 'avx512bw' for 'avx512vbmi2'.
-        ("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"],
-        // NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'.
-        ("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"],
-        ("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
-        ("aarch64", "dpb") => smallvec!["ccpp"],
-        ("aarch64", "dpb2") => smallvec!["ccdp"],
-        ("aarch64", "frintts") => smallvec!["fptoint"],
-        ("aarch64", "fcma") => smallvec!["complxnum"],
-        ("aarch64", "pmuv3") => smallvec!["perfmon"],
-        ("aarch64", "paca") => smallvec!["pauth"],
-        ("aarch64", "pacg") => smallvec!["pauth"],
-        // Rust ties fp and neon together. In LLVM neon implicitly enables fp,
-        // but we manually enable neon when a feature only implicitly enables fp
-        ("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
-        ("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
-        ("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
-        ("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
-        ("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
-        ("aarch64", "sve") => smallvec!["sve", "neon"],
-        ("aarch64", "sve2") => smallvec!["sve2", "neon"],
-        ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
-        ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
-        ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
-        ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
-        (_, s) => smallvec![s],
-    }
-}
+use crate::gcc_util::{check_tied_features, to_gcc_features};
 
 /// Get GCC attribute for the provided inline heuristic.
 #[cfg(feature="master")]
@@ -114,6 +55,19 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
         if let Some(attr) = inline_attr(cx, inline) {
             func.add_attribute(attr);
         }
+
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
+            func.add_attribute(FnAttribute::Cold);
+        }
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
+            func.add_attribute(FnAttribute::ReturnsTwice);
+        }
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
+            func.add_attribute(FnAttribute::Pure);
+        }
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
+            func.add_attribute(FnAttribute::Const);
+        }
     }
 
     let function_features =
@@ -140,11 +94,33 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
         }))
         .collect::<Vec<_>>();
 
-    // TODO(antoyo): check if we really need global backend features. (Maybe they could be applied
-    // globally?)
+    // TODO(antoyo): cg_llvm adds global features to each function so that LTO keep them.
+    // Check if GCC requires the same.
     let mut global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
     function_features.extend(&mut global_features);
-    let target_features = function_features.join(",");
+    let target_features = function_features
+        .iter()
+        .filter_map(|feature| {
+            // FIXME(antoyo): for some reasons, disabling SSE results in the following error when
+            // compiling Rust for Linux:
+            // SSE register return with SSE disabled
+            // TODO(antoyo): support soft-float and retpoline-external-thunk.
+            if feature.contains("soft-float") || feature.contains("retpoline-external-thunk") || *feature == "-sse" {
+                return None;
+            }
+
+            if feature.starts_with('-') {
+                Some(format!("no{}", feature))
+            }
+            else if feature.starts_with('+') {
+                Some(feature[1..].to_string())
+            }
+            else {
+                Some(feature.to_string())
+            }
+        })
+        .collect::<Vec<_>>()
+        .join(",");
     if !target_features.is_empty() {
         #[cfg(feature="master")]
         func.add_attribute(FnAttribute::Target(&target_features));
diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs
new file mode 100644
index 00000000000..529454b119e
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/back/lto.rs
@@ -0,0 +1,341 @@
+/// GCC requires to use the same toolchain for the whole compilation when doing LTO.
+/// So, we need the same version/commit of the linker (gcc) and lto front-end binaries (lto1,
+/// lto-wrapper, liblto_plugin.so).
+
+// FIXME(antoyo): the executables compiled with LTO are bigger than those compiled without LTO.
+// Since it is the opposite for cg_llvm, check if this is normal.
+//
+// Maybe we embed the bitcode in the final binary?
+// It doesn't look like we try to generate fat objects for the final binary.
+// Check if the way we combine the object files make it keep the LTO sections on the final link.
+// Maybe that's because the combined object files contain the IR (true) and the final link
+// does not remove it?
+//
+// TODO(antoyo): for performance, check which optimizations the C++ frontend enables.
+//
+// Fix these warnings:
+// /usr/bin/ld: warning: type of symbol `_RNvNvNvNtCs5JWOrf9uCus_5rayon11thread_pool19WORKER_THREAD_STATE7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o
+// /usr/bin/ld: warning: type of symbol `_RNvNvNvNvNtNtNtCsAj5i4SGTR7_3std4sync4mpmc5waker17current_thread_id5DUMMY7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o
+// /usr/bin/ld: warning: incremental linking of LTO and non-LTO objects; using -flinker-output=nolto-rel which will bypass whole program optimization
+
+use std::ffi::CString;
+use std::fs::{self, File};
+use std::path::{Path, PathBuf};
+
+use gccjit::OutputKind;
+use object::read::archive::ArchiveFile;
+use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule};
+use rustc_codegen_ssa::back::symbol_export;
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
+use rustc_codegen_ssa::traits::*;
+use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
+use rustc_data_structures::memmap::Mmap;
+use rustc_errors::{FatalError, Handler};
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::dep_graph::WorkProduct;
+use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
+use rustc_session::config::{CrateType, Lto};
+use tempfile::{TempDir, tempdir};
+
+use crate::back::write::save_temp_bitcode;
+use crate::errors::{
+    DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
+};
+use crate::{GccCodegenBackend, GccContext, to_gcc_opt_level};
+
+/// We keep track of the computed LTO cache keys from the previous
+/// session to determine which CGUs we can reuse.
+//pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
+
+pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
+    match crate_type {
+        CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
+        CrateType::Rlib | CrateType::ProcMacro => false,
+    }
+}
+
+struct LtoData {
+    // TODO(antoyo): use symbols_below_threshold.
+    //symbols_below_threshold: Vec<CString>,
+    upstream_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
+    tmp_path: TempDir,
+}
+
+fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler) -> Result<LtoData, FatalError> {
+    let export_threshold = match cgcx.lto {
+        // We're just doing LTO for our one crate
+        Lto::ThinLocal => SymbolExportLevel::Rust,
+
+        // We're doing LTO for the entire crate graph
+        Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&cgcx.crate_types),
+
+        Lto::No => panic!("didn't request LTO but we're doing LTO"),
+    };
+
+    let tmp_path =
+        match tempdir() {
+            Ok(tmp_path) => tmp_path,
+            Err(error) => {
+                eprintln!("Cannot create temporary directory: {}", error);
+                return Err(FatalError);
+            },
+        };
+
+    let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
+        if info.level.is_below_threshold(export_threshold) || info.used {
+            Some(CString::new(name.as_str()).unwrap())
+        } else {
+            None
+        }
+    };
+    let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
+    let mut symbols_below_threshold = {
+        let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
+        exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<CString>>()
+    };
+    info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
+
+    // If we're performing LTO for the entire crate graph, then for each of our
+    // upstream dependencies, find the corresponding rlib and load the bitcode
+    // from the archive.
+    //
+    // We save off all the bytecode and GCC module file path for later processing
+    // with either fat or thin LTO
+    let mut upstream_modules = Vec::new();
+    if cgcx.lto != Lto::ThinLocal {
+        // Make sure we actually can run LTO
+        for crate_type in cgcx.crate_types.iter() {
+            if !crate_type_allows_lto(*crate_type) {
+                diag_handler.emit_err(LtoDisallowed);
+                return Err(FatalError);
+            } else if *crate_type == CrateType::Dylib {
+                if !cgcx.opts.unstable_opts.dylib_lto {
+                    diag_handler.emit_err(LtoDylib);
+                    return Err(FatalError);
+                }
+            }
+        }
+
+        if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
+            diag_handler.emit_err(DynamicLinkingWithLTO);
+            return Err(FatalError);
+        }
+
+        for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
+            let exported_symbols =
+                cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
+            {
+                let _timer =
+                    cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
+                symbols_below_threshold
+                    .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter));
+            }
+
+            let archive_data = unsafe {
+                Mmap::map(File::open(&path).expect("couldn't open rlib"))
+                    .expect("couldn't map rlib")
+            };
+            let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
+            let obj_files = archive
+                .members()
+                .filter_map(|child| {
+                    child.ok().and_then(|c| {
+                        std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c))
+                    })
+                })
+                .filter(|&(name, _)| looks_like_rust_object_file(name));
+            for (name, child) in obj_files {
+                info!("adding bitcode from {}", name);
+                let path = tmp_path.path().join(name);
+                match save_as_file(child.data(&*archive_data).expect("corrupt rlib"), &path) {
+                    Ok(()) => {
+                        let buffer = ModuleBuffer::new(path);
+                        let module = SerializedModule::Local(buffer);
+                        upstream_modules.push((module, CString::new(name).unwrap()));
+                    }
+                    Err(e) => {
+                        diag_handler.emit_err(e);
+                        return Err(FatalError);
+                    }
+                }
+            }
+        }
+    }
+
+    Ok(LtoData {
+        //symbols_below_threshold,
+        upstream_modules,
+        tmp_path,
+    })
+}
+
+fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> {
+    fs::write(path, obj)
+        .map_err(|error| LtoBitcodeFromRlib {
+            gcc_err: format!("write object file to temp dir: {}", error)
+        })
+}
+
+/// Performs fat LTO by merging all modules into a single one and returning it
+/// for further optimization.
+pub(crate) fn run_fat(
+    cgcx: &CodegenContext<GccCodegenBackend>,
+    modules: Vec<FatLtoInput<GccCodegenBackend>>,
+    cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
+) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
+    let diag_handler = cgcx.create_diag_handler();
+    let lto_data = prepare_lto(cgcx, &diag_handler)?;
+    /*let symbols_below_threshold =
+        lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
+    fat_lto(cgcx, &diag_handler, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path,
+        //&symbols_below_threshold,
+    )
+}
+
+fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir,
+    //symbols_below_threshold: &[*const libc::c_char],
+) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
+    let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
+    info!("going for a fat lto");
+
+    // Sort out all our lists of incoming modules into two lists.
+    //
+    // * `serialized_modules` (also and argument to this function) contains all
+    //   modules that are serialized in-memory.
+    // * `in_memory` contains modules which are already parsed and in-memory,
+    //   such as from multi-CGU builds.
+    //
+    // All of `cached_modules` (cached from previous incremental builds) can
+    // immediately go onto the `serialized_modules` modules list and then we can
+    // split the `modules` array into these two lists.
+    let mut in_memory = Vec::new();
+    serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| {
+        info!("pushing cached module {:?}", wp.cgu_name);
+        (buffer, CString::new(wp.cgu_name).unwrap())
+    }));
+    for module in modules {
+        match module {
+            FatLtoInput::InMemory(m) => in_memory.push(m),
+            FatLtoInput::Serialized { name, buffer } => {
+                info!("pushing serialized module {:?}", name);
+                let buffer = SerializedModule::Local(buffer);
+                serialized_modules.push((buffer, CString::new(name).unwrap()));
+            }
+        }
+    }
+
+    // Find the "costliest" module and merge everything into that codegen unit.
+    // All the other modules will be serialized and reparsed into the new
+    // context, so this hopefully avoids serializing and parsing the largest
+    // codegen unit.
+    //
+    // Additionally use a regular module as the base here to ensure that various
+    // file copy operations in the backend work correctly. The only other kind
+    // of module here should be an allocator one, and if your crate is smaller
+    // than the allocator module then the size doesn't really matter anyway.
+    let costliest_module = in_memory
+        .iter()
+        .enumerate()
+        .filter(|&(_, module)| module.kind == ModuleKind::Regular)
+        .map(|(i, _module)| {
+            //let cost = unsafe { llvm::LLVMRustModuleCost(module.module_llvm.llmod()) };
+            // TODO(antoyo): compute the cost of a module if GCC allows this.
+            (0, i)
+        })
+        .max();
+
+    // If we found a costliest module, we're good to go. Otherwise all our
+    // inputs were serialized which could happen in the case, for example, that
+    // all our inputs were incrementally reread from the cache and we're just
+    // re-executing the LTO passes. If that's the case deserialize the first
+    // module and create a linker with it.
+    let mut module: ModuleCodegen<GccContext> = match costliest_module {
+        Some((_cost, i)) => in_memory.remove(i),
+        None => {
+            unimplemented!("Incremental");
+            /*assert!(!serialized_modules.is_empty(), "must have at least one serialized module");
+            let (buffer, name) = serialized_modules.remove(0);
+            info!("no in-memory regular modules to choose from, parsing {:?}", name);
+            ModuleCodegen {
+                module_llvm: GccContext::parse(cgcx, &name, buffer.data(), diag_handler)?,
+                name: name.into_string().unwrap(),
+                kind: ModuleKind::Regular,
+            }*/
+        }
+    };
+    let mut serialized_bitcode = Vec::new();
+    {
+        info!("using {:?} as a base module", module.name);
+
+        // We cannot load and merge GCC contexts in memory like cg_llvm is doing.
+        // Instead, we combine the object files into a single object file.
+        for module in in_memory {
+            let path = tmp_path.path().to_path_buf().join(&module.name);
+            let path = path.to_str().expect("path");
+            let context = &module.module_llvm.context;
+            let config = cgcx.config(module.kind);
+            // NOTE: we need to set the optimization level here in order for LTO to do its job.
+            context.set_optimization_level(to_gcc_opt_level(config.opt_level));
+            context.add_command_line_option("-flto=auto");
+            context.add_command_line_option("-flto-partition=one");
+            context.compile_to_file(OutputKind::ObjectFile, path);
+            let buffer = ModuleBuffer::new(PathBuf::from(path));
+            let llmod_id = CString::new(&module.name[..]).unwrap();
+            serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
+        }
+        // Sort the modules to ensure we produce deterministic results.
+        serialized_modules.sort_by(|module1, module2| module1.1.cmp(&module2.1));
+
+        // We add the object files and save in should_combine_object_files that we should combine
+        // them into a single object file when compiling later.
+        for (bc_decoded, name) in serialized_modules {
+            let _timer = cgcx
+                .prof
+                .generic_activity_with_arg_recorder("GCC_fat_lto_link_module", |recorder| {
+                    recorder.record_arg(format!("{:?}", name))
+                });
+            info!("linking {:?}", name);
+            match bc_decoded {
+                SerializedModule::Local(ref module_buffer) => {
+                    module.module_llvm.should_combine_object_files = true;
+                    module.module_llvm.context.add_driver_option(module_buffer.0.to_str().expect("path"));
+                },
+                SerializedModule::FromRlib(_) => unimplemented!("from rlib"),
+                SerializedModule::FromUncompressedFile(_) => unimplemented!("from uncompressed file"),
+            }
+            serialized_bitcode.push(bc_decoded);
+        }
+        save_temp_bitcode(cgcx, &module, "lto.input");
+
+        // Internalize everything below threshold to help strip out more modules and such.
+        /*unsafe {
+            let ptr = symbols_below_threshold.as_ptr();
+            llvm::LLVMRustRunRestrictionPass(
+                llmod,
+                ptr as *const *const libc::c_char,
+                symbols_below_threshold.len() as libc::size_t,
+            );*/
+            save_temp_bitcode(cgcx, &module, "lto.after-restriction");
+        //}
+    }
+
+    // NOTE: save the temporary directory used by LTO so that it gets deleted after linking instead
+    // of now.
+    module.module_llvm.temp_dir = Some(tmp_path);
+
+    Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
+}
+
+pub struct ModuleBuffer(PathBuf);
+
+impl ModuleBuffer {
+    pub fn new(path: PathBuf) -> ModuleBuffer {
+        ModuleBuffer(path)
+    }
+}
+
+impl ModuleBufferMethods for ModuleBuffer {
+    fn data(&self) -> &[u8] {
+        unimplemented!("data not needed for GCC codegen");
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/back/mod.rs b/compiler/rustc_codegen_gcc/src/back/mod.rs
index d692799d764..10187eab0d7 100644
--- a/compiler/rustc_codegen_gcc/src/back/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/back/mod.rs
@@ -1 +1,2 @@
+pub mod lto;
 pub mod write;
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index 5f54ac4ebc6..04772d7707a 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -2,27 +2,71 @@ use std::{env, fs};
 
 use gccjit::OutputKind;
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
-use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig};
+use rustc_codegen_ssa::back::link::ensure_removed;
+use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
 use rustc_errors::Handler;
+use rustc_fs_util::link_or_copy;
 use rustc_session::config::OutputType;
 use rustc_span::fatal_error::FatalError;
 use rustc_target::spec::SplitDebuginfo;
 
 use crate::{GccCodegenBackend, GccContext};
+use crate::errors::CopyBitcode;
 
-pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
-    let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name);
+pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+    let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name);
     {
         let context = &module.module_llvm.context;
 
         let module_name = module.name.clone();
+
+        let should_combine_object_files = module.module_llvm.should_combine_object_files;
+
         let module_name = Some(&module_name[..]);
 
-        let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+        // NOTE: Only generate object files with GIMPLE when this environment variable is set for
+        // now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
+        let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1");
+
+        let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
         let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
 
-        if config.bitcode_needed() {
+        if config.bitcode_needed() && fat_lto {
+            let _timer = cgcx
+                .prof
+                .generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
+
             // TODO(antoyo)
+            /*if let Some(bitcode_filename) = bc_out.file_name() {
+                cgcx.prof.artifact_size(
+                    "llvm_bitcode",
+                    bitcode_filename.to_string_lossy(),
+                    data.len() as u64,
+                );
+            }*/
+
+            if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+                let _timer = cgcx
+                    .prof
+                    .generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name);
+                context.add_command_line_option("-flto=auto");
+                context.add_command_line_option("-flto-partition=one");
+                context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
+            }
+
+            if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
+                let _timer = cgcx
+                    .prof
+                    .generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name);
+                // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
+                //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
+
+                context.add_command_line_option("-flto=auto");
+                context.add_command_line_option("-flto-partition=one");
+                context.add_command_line_option("-ffat-lto-objects");
+                // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
+                context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
+            }
         }
 
         if config.emit_ir {
@@ -32,7 +76,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
         if config.emit_asm {
             let _timer = cgcx
                 .prof
-                .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name);
+                .generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name);
             let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
             context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
         }
@@ -41,7 +85,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
             EmitObj::ObjectCode(_) => {
                 let _timer = cgcx
                     .prof
-                    .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
+                    .generic_activity_with_arg("GCC_module_codegen_emit_obj", &*module.name);
                 if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") {
                     println!("Module {}", module.name);
                 }
@@ -60,11 +104,36 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
                     context.set_debug_info(true);
                     context.dump_to_file(path, true);
                 }
-                context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
+                if should_combine_object_files && fat_lto {
+                    context.add_command_line_option("-flto=auto");
+                    context.add_command_line_option("-flto-partition=one");
+
+                    context.add_driver_option("-Wl,-r");
+                    // NOTE: we need -nostdlib, otherwise, we get the following error:
+                    // /usr/bin/ld: cannot find -lgcc_s: No such file or directory
+                    context.add_driver_option("-nostdlib");
+                    // NOTE: without -fuse-linker-plugin, we get the following error:
+                    // lto1: internal compiler error: decompressed stream: Destination buffer is too small
+                    context.add_driver_option("-fuse-linker-plugin");
+
+                    // NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o.
+                    context.compile_to_file(OutputKind::Executable, obj_out.to_str().expect("path to str"));
+                }
+                else {
+                    context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
+                }
             }
 
             EmitObj::Bitcode => {
-                // TODO(antoyo)
+                debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
+                if let Err(err) = link_or_copy(&bc_out, &obj_out) {
+                    diag_handler.emit_err(CopyBitcode { err });
+                }
+
+                if !config.emit_bc {
+                    debug!("removing_bitcode {:?}", bc_out);
+                    ensure_removed(diag_handler, &bc_out);
+                }
             }
 
             EmitObj::None => {}
@@ -82,3 +151,18 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
 pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
     unimplemented!();
 }
+
+pub(crate) fn save_temp_bitcode(cgcx: &CodegenContext<GccCodegenBackend>, _module: &ModuleCodegen<GccContext>, _name: &str) {
+    if !cgcx.save_temps {
+        return;
+    }
+    unimplemented!();
+    /*unsafe {
+        let ext = format!("{}.bc", name);
+        let cgu = Some(&module.name[..]);
+        let path = cgcx.output_filenames.temp_path_ext(&ext, cgu);
+        let cstr = path_to_c_string(&path);
+        let llmod = module.module_llvm.llmod();
+        llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
+    }*/
+}
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index 9e614ca4ace..b081e9ff2fd 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -1,3 +1,4 @@
+use std::collections::HashSet;
 use std::env;
 use std::time::Instant;
 
@@ -18,6 +19,7 @@ use rustc_codegen_ssa::traits::DebugInfoMethods;
 use rustc_session::config::DebugInfo;
 use rustc_span::Symbol;
 
+use crate::{LockedTargetInfo, gcc_util};
 use crate::GccContext;
 use crate::builder::Builder;
 use crate::context::CodegenCx;
@@ -50,6 +52,7 @@ pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
 pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
     match linkage {
         Linkage::External => FunctionType::Exported,
+        // TODO(antoyo): set the attribute externally_visible.
         Linkage::AvailableExternally => FunctionType::Extern,
         Linkage::LinkOnceAny => unimplemented!(),
         Linkage::LinkOnceODR => unimplemented!(),
@@ -63,7 +66,7 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
     }
 }
 
-pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_integers: bool) -> (ModuleCodegen<GccContext>, u64) {
+pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: LockedTargetInfo) -> (ModuleCodegen<GccContext>, u64) {
     let prof_timer = tcx.prof.generic_activity("codegen_module");
     let start_time = Instant::now();
 
@@ -71,7 +74,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
     let (module, _) = tcx.dep_graph.with_task(
         dep_node,
         tcx,
-        (cgu_name, supports_128bit_integers),
+        (cgu_name, target_info),
         module_codegen,
         Some(dep_graph::hash_result),
     );
@@ -82,38 +85,28 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
     // the time we needed for codegenning it.
     let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
 
-    fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, supports_128bit_integers): (Symbol, bool)) -> ModuleCodegen<GccContext> {
+    fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen<GccContext> {
         let cgu = tcx.codegen_unit(cgu_name);
         // Instantiate monomorphizations without filling out definitions yet...
-        //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
         let context = Context::default();
 
         context.add_command_line_option("-fexceptions");
         context.add_driver_option("-fexceptions");
 
+        let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',')
+            .filter(|feature| feature.starts_with('-'))
+            .map(|string| &string[1..])
+            .collect();
+
         // TODO(antoyo): only set on x86 platforms.
         context.add_command_line_option("-masm=intel");
-        // TODO(antoyo): only add the following cli argument if the feature is supported.
-        context.add_command_line_option("-msse2");
-        context.add_command_line_option("-mavx2");
-        // FIXME(antoyo): the following causes an illegal instruction on vmovdqu64 in std_example on my CPU.
-        // Only add if the CPU supports it.
-        context.add_command_line_option("-msha");
-        context.add_command_line_option("-mpclmul");
-        context.add_command_line_option("-mfma");
-        context.add_command_line_option("-mfma4");
-        context.add_command_line_option("-m64");
-        context.add_command_line_option("-mbmi");
-        context.add_command_line_option("-mgfni");
-        //context.add_command_line_option("-mavxvnni"); // The CI doesn't support this option.
-        context.add_command_line_option("-mf16c");
-        context.add_command_line_option("-maes");
-        context.add_command_line_option("-mxsavec");
-        context.add_command_line_option("-mbmi2");
-        context.add_command_line_option("-mrtm");
-        context.add_command_line_option("-mvaes");
-        context.add_command_line_option("-mvpclmulqdq");
-        context.add_command_line_option("-mavx");
+
+        if !disabled_features.contains("avx") {
+            // NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for
+            // SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead.
+            // FIXME(antoyo): use the proper builtins for llvm.x86.sse2.cmp.pd and similar.
+            context.add_command_line_option("-mavx");
+        }
 
         for arg in &tcx.sess.opts.cg.llvm_args {
             context.add_command_line_option(arg);
@@ -127,6 +120,16 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
         // NOTE: Rust relies on LLVM doing wrapping on overflow.
         context.add_command_line_option("-fwrapv");
 
+        if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static {
+            context.add_command_line_option("-mcmodel=kernel");
+            context.add_command_line_option("-fno-pie");
+        }
+
+        let target_cpu = gcc_util::target_cpu(tcx.sess);
+        if target_cpu != "generic" {
+            context.add_command_line_option(&format!("-march={}", target_cpu));
+        }
+
         if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) {
             context.add_command_line_option("-ffunction-sections");
             context.add_command_line_option("-fdata-sections");
@@ -135,8 +138,14 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
         if env::var("CG_GCCJIT_DUMP_RTL").as_deref() == Ok("1") {
             context.add_command_line_option("-fdump-rtl-vregs");
         }
+        if env::var("CG_GCCJIT_DUMP_RTL_ALL").as_deref() == Ok("1") {
+            context.add_command_line_option("-fdump-rtl-all");
+        }
         if env::var("CG_GCCJIT_DUMP_TREE_ALL").as_deref() == Ok("1") {
-            context.add_command_line_option("-fdump-tree-all");
+            context.add_command_line_option("-fdump-tree-all-eh");
+        }
+        if env::var("CG_GCCJIT_DUMP_IPA_ALL").as_deref() == Ok("1") {
+            context.add_command_line_option("-fdump-ipa-all-eh");
         }
         if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
             context.set_dump_code_on_compile(true);
@@ -152,11 +161,15 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
             context.set_keep_intermediates(true);
         }
 
+        if env::var("CG_GCCJIT_VERBOSE").as_deref() == Ok("1") {
+            context.add_driver_option("-v");
+        }
+
         // NOTE: The codegen generates unrechable blocks.
         context.set_allow_unreachable_blocks(true);
 
         {
-            let cx = CodegenCx::new(&context, cgu, tcx, supports_128bit_integers);
+            let cx = CodegenCx::new(&context, cgu, tcx, target_info.supports_128bit_int());
 
             let mono_items = cgu.items_in_deterministic_order(tcx);
             for &(mono_item, data) in &mono_items {
@@ -181,7 +194,9 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
         ModuleCodegen {
             name: cgu_name.to_string(),
             module_llvm: GccContext {
-                context
+                context,
+                should_combine_object_files: false,
+                temp_dir: None,
             },
             kind: ModuleKind::Regular,
         }
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index ecc293aee23..b7841808934 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -247,16 +247,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
     }
 
     fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
-        let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here.
         let stored_ty = self.cx.val_ty(val);
         let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
-
-        if dest_ptr_ty == stored_ptr_ty {
-            ptr
-        }
-        else {
-            self.bitcast(ptr, stored_ptr_ty)
-        }
+        self.bitcast(ptr, stored_ptr_ty)
     }
 
     pub fn current_func(&self) -> Function<'gcc> {
@@ -500,7 +493,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     #[cfg(not(feature="master"))]
-    fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: &CodegenFnAttrs, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+    fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
         let call_site = self.call(typ, fn_attrs, None, func, args, None);
         let condition = self.context.new_rvalue_from_int(self.bool_type, 1);
         self.llbb().end_with_conditional(None, condition, then, catch);
@@ -663,7 +656,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        a + b
+        self.gcc_add(a, b)
     }
 
     fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -671,7 +664,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        a - b
+        self.gcc_sub(a, b)
     }
 
     fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -680,11 +673,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        a * b
+        self.gcc_mul(a, b)
     }
 
     fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        a * b
+        self.gcc_mul(a, b)
     }
 
     fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
@@ -916,7 +909,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
             .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering]));
     }
 
-    fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+    fn gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+        // NOTE: due to opaque pointers now being used, we need to cast here.
+        let ptr = self.context.new_cast(None, ptr, typ.make_pointer());
         let ptr_type = ptr.get_type();
         let mut pointee_type = ptr.get_type();
         // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is
@@ -927,6 +922,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         // require dereferencing the pointer.
         for index in indices {
             pointee_type = pointee_type.get_pointee().expect("pointee type");
+            #[cfg(feature="master")]
+            let pointee_size = {
+                let size = self.cx.context.new_sizeof(pointee_type);
+                self.context.new_cast(None, size, index.get_type())
+            };
+            #[cfg(not(feature="master"))]
             let pointee_size = self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32);
             result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type);
         }
diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs
index 493626c3cf5..e673d0af4c7 100644
--- a/compiler/rustc_codegen_gcc/src/declare.rs
+++ b/compiler/rustc_codegen_gcc/src/declare.rs
@@ -1,4 +1,6 @@
 use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
+#[cfg(feature="master")]
+use gccjit::{FnAttribute, ToRValue};
 use rustc_codegen_ssa::traits::BaseTypeMethods;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
@@ -114,6 +116,44 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll
                 .collect();
             let func = cx.context.new_function(None, cx.linkage.get(), return_type, &params, mangle_name(name), variadic);
             cx.functions.borrow_mut().insert(name.to_string(), func);
+
+            #[cfg(feature="master")]
+            if name == "rust_eh_personality" {
+                // NOTE: GCC will sometimes change the personality function set on a function from
+                // rust_eh_personality to __gcc_personality_v0 as an optimization.
+                // As such, we need to create a weak alias from __gcc_personality_v0 to
+                // rust_eh_personality in order to avoid a linker error.
+                // This needs to be weak in order to still allow using the standard
+                // __gcc_personality_v0 when the linking to it.
+                // Since aliases don't work (maybe because of a bug in LTO partitioning?), we
+                // create a wrapper function that calls rust_eh_personality.
+
+                let params: Vec<_> = param_types.into_iter().enumerate()
+                    .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
+                    .collect();
+                let gcc_func = cx.context.new_function(None, FunctionType::Exported, return_type, &params, "__gcc_personality_v0", variadic);
+
+                // We need a normal extern function for the crates that access rust_eh_personality
+                // without defining it, otherwise we'll get a compiler error.
+                //
+                // For the crate defining it, that needs to be a weak alias instead.
+                gcc_func.add_attribute(FnAttribute::Weak);
+
+                let block = gcc_func.new_block("start");
+                let mut args = vec![];
+                for param in &params {
+                    args.push(param.to_rvalue());
+                }
+                let call = cx.context.new_call(None, func, &args);
+                if return_type == cx.type_void() {
+                    block.add_eval(None, call);
+                    block.end_with_void_return(None);
+                }
+                else {
+                    block.end_with_return(None, call);
+                }
+            }
+
             func
         };
 
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index 693367192b1..4bf3b71f503 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -1,8 +1,36 @@
-use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
-use rustc_macros::Diagnostic;
+use rustc_errors::{
+    DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, IntoDiagnosticArg,
+};
+use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
 use std::borrow::Cow;
 
+use crate::fluent_generated as fluent;
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
+#[note]
+pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
+    pub feature: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_unknown_ctarget_feature)]
+#[note]
+pub(crate) struct UnknownCTargetFeature<'a> {
+    pub feature: &'a str,
+    #[subdiagnostic]
+    pub rust_feature: PossibleFeature<'a>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum PossibleFeature<'a> {
+    #[help(codegen_gcc_possible_feature)]
+    Some { rust_feature: &'a str },
+    #[help(codegen_gcc_consider_filing_feature_request)]
+    None,
+}
+
 struct ExitCode(Option<i32>);
 
 impl IntoDiagnosticArg for ExitCode {
@@ -40,3 +68,58 @@ pub(crate) struct TiedTargetFeatures {
     pub span: Span,
     pub features: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_copy_bitcode)]
+pub(crate) struct CopyBitcode {
+    pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_dynamic_linking_with_lto)]
+#[note]
+pub(crate) struct DynamicLinkingWithLTO;
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_load_bitcode)]
+pub(crate) struct LoadBitcode {
+    name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_lto_disallowed)]
+pub(crate) struct LtoDisallowed;
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_lto_dylib)]
+pub(crate) struct LtoDylib;
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_lto_bitcode_from_rlib)]
+pub(crate) struct LtoBitcodeFromRlib {
+    pub gcc_err: String,
+}
+
+pub(crate) struct TargetFeatureDisableOrEnable<'a> {
+    pub features: &'a [&'a str],
+    pub span: Option<Span>,
+    pub missing_features: Option<MissingFeatures>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(codegen_gcc_missing_features)]
+pub(crate) struct MissingFeatures;
+
+impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
+    fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
+        if let Some(span) = self.span {
+            diag.set_span(span);
+        };
+        if let Some(missing_features) = self.missing_features {
+            diag.subdiagnostic(missing_features);
+        }
+        diag.set_arg("features", self.features.join(", "));
+        diag
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
new file mode 100644
index 00000000000..0514c9988e0
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -0,0 +1,223 @@
+#[cfg(feature="master")]
+use gccjit::Context;
+use smallvec::{smallvec, SmallVec};
+
+use rustc_codegen_ssa::target_features::{
+    supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
+};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::bug;
+use rustc_session::Session;
+
+use crate::errors::{PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
+
+/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
+/// `--target` and similar).
+pub(crate) fn global_gcc_features(sess: &Session, diagnostics: 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:
+    //
+    // * Features from -Ctarget-cpu=*; are overridden by [^1]
+    // * Features implied by --target; are overridden by
+    // * Features from -Ctarget-feature; are overridden by
+    // * function specific features.
+    //
+    // [^1]: target-cpu=native is handled here, other target-cpu values are handled implicitly
+    // through GCC march implementation.
+    //
+    // FIXME(nagisa): it isn't clear what's the best interaction between features implied by
+    // `-Ctarget-cpu` and `--target` are. On one hand, you'd expect CLI arguments to always
+    // override anything that's implicit, so e.g. when there's no `--target` flag, features implied
+    // the host target are overridden by `-Ctarget-cpu=*`. On the other hand, what about when both
+    // `--target` and `-Ctarget-cpu=*` are specified? Both then imply some target features and both
+    // flags are specified by the user on the CLI. It isn't as clear-cut which order of precedence
+    // should be taken in cases like these.
+    let mut features = vec![];
+
+    // Features implied by an implicit or explicit `--target`.
+    features.extend(
+        sess.target
+            .features
+            .split(',')
+            .filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
+            .map(String::from),
+    );
+
+    // -Ctarget-features
+    let supported_features = supported_target_features(sess);
+    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.emit_warning(UnknownCTargetFeaturePrefix { feature: s });
+                    }
+                    return None;
+                }
+            };
+
+            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, _)| {
+                    let gcc_features = to_gcc_features(sess, rust_feature);
+                    if gcc_features.contains(&feature) && !gcc_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 {
+                        UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                    };
+                sess.emit_warning(unknown_feature);
+            }
+
+            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 GCC…
+            if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+                return None;
+            }
+            // ... otherwise though we run through `to_gcc_features` when
+            // passing requests down to GCC. This means that all in-language
+            // features also work on the command line instead of having two
+            // different names when the GCC name and the Rust name differ.
+            Some(to_gcc_features(sess, feature)
+                .iter()
+                .flat_map(|feat| to_gcc_features(sess, feat).into_iter())
+                .map(|feature| {
+                    if enable_disable == '-' {
+                        format!("-{}", feature)
+                    }
+                    else {
+                        feature.to_string()
+                    }
+                })
+                .collect::<Vec<_>>(),
+            )
+        })
+        .flatten();
+    features.extend(feats);
+
+    if diagnostics {
+        if let Some(f) = check_tied_features(sess, &featsmap) {
+            sess.emit_err(TargetFeatureDisableOrEnable {
+                features: f,
+                span: None,
+                missing_features: None,
+            });
+        }
+    }
+
+    features
+}
+
+/// Returns a feature name for the given `+feature` or `-feature` string.
+///
+/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
+fn backend_feature_name(s: &str) -> Option<&str> {
+    // features must start with a `+` or `-`.
+    let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| {
+        bug!("target feature `{}` must begin with a `+` or `-`", s);
+    });
+    // Rustc-specific feature requests like `+crt-static` or `-crt-static`
+    // are not passed down to GCC.
+    if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+        return None;
+    }
+    Some(feature)
+}
+
+// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
+    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
+    match (arch, s) {
+        ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
+        ("x86", "pclmulqdq") => smallvec!["pclmul"],
+        ("x86", "rdrand") => smallvec!["rdrnd"],
+        ("x86", "bmi1") => smallvec!["bmi"],
+        ("x86", "cmpxchg16b") => smallvec!["cx16"],
+        ("x86", "avx512vaes") => smallvec!["vaes"],
+        ("x86", "avx512gfni") => smallvec!["gfni"],
+        ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
+        // NOTE: seems like GCC requires 'avx512bw' for 'avx512vbmi2'.
+        ("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"],
+        // NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'.
+        ("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"],
+        ("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
+        ("aarch64", "dpb") => smallvec!["ccpp"],
+        ("aarch64", "dpb2") => smallvec!["ccdp"],
+        ("aarch64", "frintts") => smallvec!["fptoint"],
+        ("aarch64", "fcma") => smallvec!["complxnum"],
+        ("aarch64", "pmuv3") => smallvec!["perfmon"],
+        ("aarch64", "paca") => smallvec!["pauth"],
+        ("aarch64", "pacg") => smallvec!["pauth"],
+        // Rust ties fp and neon together. In GCC neon implicitly enables fp,
+        // but we manually enable neon when a feature only implicitly enables fp
+        ("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
+        ("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
+        ("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
+        ("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
+        ("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
+        ("aarch64", "sve") => smallvec!["sve", "neon"],
+        ("aarch64", "sve2") => smallvec!["sve2", "neon"],
+        ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
+        ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
+        ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
+        ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
+        (_, s) => smallvec![s],
+    }
+}
+
+// Given a map from target_features to whether they are enabled or disabled,
+// ensure only valid combinations are allowed.
+pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> {
+    for tied in tied_target_features(sess) {
+        // Tied features must be set to the same value, or not set at all
+        let mut tied_iter = tied.iter();
+        let enabled = features.get(tied_iter.next().unwrap());
+        if tied_iter.any(|feature| enabled != features.get(feature)) {
+            return Some(tied);
+        }
+    }
+    None
+}
+
+fn handle_native(name: &str) -> &str {
+    if name != "native" {
+        return name;
+    }
+
+    #[cfg(feature="master")]
+    {
+        // Get the native arch.
+        let context = Context::default();
+        context.get_target_info().arch().unwrap()
+            .to_str()
+            .unwrap()
+    }
+    #[cfg(not(feature="master"))]
+    unimplemented!();
+}
+
+pub fn target_cpu(sess: &Session) -> &str {
+    match sess.opts.cg.target_cpu {
+        Some(ref name) => handle_native(name),
+        None => handle_native(sess.target.cpu.as_ref()),
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index 0cf1204791d..58e0dd56f38 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -36,7 +36,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             self.cx.context.new_unary_op(None, operation, typ, a)
         }
         else {
-            // TODO(antoyo): use __negdi2 and __negti2 instead?
             let element_type = typ.dyncast_array().expect("element type");
             let values = [
                 self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)),
@@ -52,9 +51,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
         }
         else {
-            let param_a = self.context.new_parameter(None, a_type, "a");
-            let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a], "__negti2", false);
-            self.context.new_call(None, func, &[a])
+            self.gcc_add(self.gcc_not(a), self.gcc_int(a_type, 1))
         }
     }
 
@@ -353,23 +350,63 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         (res.dereference(None).to_rvalue(), overflow)
     }
 
-    pub fn gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
+    pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
         let a_type = lhs.get_type();
         let b_type = rhs.get_type();
         if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) {
-            let signed = a_type.is_compatible_with(self.i128_type);
-            let sign =
-                if signed {
-                    ""
-                }
-                else {
-                    "u"
-                };
-            let func_name = format!("__{}cmpti2", sign);
-            let param_a = self.context.new_parameter(None, a_type, "a");
-            let param_b = self.context.new_parameter(None, b_type, "b");
-            let func = self.context.new_function(None, FunctionType::Extern, self.int_type, &[param_a, param_b], func_name, false);
-            let cmp = self.context.new_call(None, func, &[lhs, rhs]);
+            // This algorithm is based on compiler-rt's __cmpti2:
+            // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21
+            let result = self.current_func().new_local(None, self.int_type, "icmp_result");
+            let block1 = self.current_func().new_block("block1");
+            let block2 = self.current_func().new_block("block2");
+            let block3 = self.current_func().new_block("block3");
+            let block4 = self.current_func().new_block("block4");
+            let block5 = self.current_func().new_block("block5");
+            let block6 = self.current_func().new_block("block6");
+            let block7 = self.current_func().new_block("block7");
+            let block8 = self.current_func().new_block("block8");
+            let after = self.current_func().new_block("after");
+
+            let native_int_type = a_type.dyncast_array().expect("get element type");
+            // NOTE: cast low to its unsigned type in order to perform a comparison correctly (e.g.
+            // the sign is only on high).
+            let unsigned_type = native_int_type.to_unsigned(&self.cx);
+
+            let lhs_low = self.context.new_cast(None, self.low(lhs), unsigned_type);
+            let rhs_low = self.context.new_cast(None, self.low(rhs), unsigned_type);
+
+            let condition = self.context.new_comparison(None, ComparisonOp::LessThan, self.high(lhs), self.high(rhs));
+            self.llbb().end_with_conditional(None, condition, block1, block2);
+
+            block1.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type));
+            block1.end_with_jump(None, after);
+
+            let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs));
+            block2.end_with_conditional(None, condition, block3, block4);
+
+            block3.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2));
+            block3.end_with_jump(None, after);
+
+            let condition = self.context.new_comparison(None, ComparisonOp::LessThan, lhs_low, rhs_low);
+            block4.end_with_conditional(None, condition, block5, block6);
+
+            block5.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type));
+            block5.end_with_jump(None, after);
+
+            let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, lhs_low, rhs_low);
+            block6.end_with_conditional(None, condition, block7, block8);
+
+            block7.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2));
+            block7.end_with_jump(None, after);
+
+            block8.add_assignment(None, result, self.context.new_rvalue_one(self.int_type));
+            block8.end_with_jump(None, after);
+
+            // NOTE: since jumps were added in a place rustc does not expect, the current block in the
+            // state need to be updated.
+            self.switch_to_block(after);
+
+            let cmp = result.to_rvalue();
             let (op, limit) =
                 match op {
                     IntPredicate::IntEQ => {
@@ -546,7 +583,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 
     pub fn gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
-        if self.is_native_int_type_or_bool(typ) {
+        if typ.is_u128(self) {
+            // FIXME(antoyo): libgccjit cannot create 128-bit values yet.
+            let num = self.context.new_rvalue_from_long(self.u64_type, int as i64);
+            self.gcc_int_cast(num, typ)
+        }
+        else if self.is_native_int_type_or_bool(typ) {
             self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64)
         }
         else {
@@ -572,6 +614,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
             }
         }
         else if typ.is_i128(self) {
+            // FIXME(antoyo): libgccjit cannot create 128-bit values yet.
             let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
             self.gcc_int_cast(num, typ)
         }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs
index 438eab78943..e01299d32fd 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs
@@ -2254,6 +2254,42 @@ match name {
     "llvm.hexagon.prefetch" => "__builtin_HEXAGON_prefetch",
     "llvm.hexagon.vmemcpy" => "__builtin_hexagon_vmemcpy",
     "llvm.hexagon.vmemset" => "__builtin_hexagon_vmemset",
+    // loongarch
+    "llvm.loongarch.asrtgt.d" => "__builtin_loongarch_asrtgt_d",
+    "llvm.loongarch.asrtle.d" => "__builtin_loongarch_asrtle_d",
+    "llvm.loongarch.break" => "__builtin_loongarch_break",
+    "llvm.loongarch.cacop.d" => "__builtin_loongarch_cacop_d",
+    "llvm.loongarch.cacop.w" => "__builtin_loongarch_cacop_w",
+    "llvm.loongarch.cpucfg" => "__builtin_loongarch_cpucfg",
+    "llvm.loongarch.crc.w.b.w" => "__builtin_loongarch_crc_w_b_w",
+    "llvm.loongarch.crc.w.d.w" => "__builtin_loongarch_crc_w_d_w",
+    "llvm.loongarch.crc.w.h.w" => "__builtin_loongarch_crc_w_h_w",
+    "llvm.loongarch.crc.w.w.w" => "__builtin_loongarch_crc_w_w_w",
+    "llvm.loongarch.crcc.w.b.w" => "__builtin_loongarch_crcc_w_b_w",
+    "llvm.loongarch.crcc.w.d.w" => "__builtin_loongarch_crcc_w_d_w",
+    "llvm.loongarch.crcc.w.h.w" => "__builtin_loongarch_crcc_w_h_w",
+    "llvm.loongarch.crcc.w.w.w" => "__builtin_loongarch_crcc_w_w_w",
+    "llvm.loongarch.csrrd.d" => "__builtin_loongarch_csrrd_d",
+    "llvm.loongarch.csrrd.w" => "__builtin_loongarch_csrrd_w",
+    "llvm.loongarch.csrwr.d" => "__builtin_loongarch_csrwr_d",
+    "llvm.loongarch.csrwr.w" => "__builtin_loongarch_csrwr_w",
+    "llvm.loongarch.csrxchg.d" => "__builtin_loongarch_csrxchg_d",
+    "llvm.loongarch.csrxchg.w" => "__builtin_loongarch_csrxchg_w",
+    "llvm.loongarch.dbar" => "__builtin_loongarch_dbar",
+    "llvm.loongarch.ibar" => "__builtin_loongarch_ibar",
+    "llvm.loongarch.iocsrrd.b" => "__builtin_loongarch_iocsrrd_b",
+    "llvm.loongarch.iocsrrd.d" => "__builtin_loongarch_iocsrrd_d",
+    "llvm.loongarch.iocsrrd.h" => "__builtin_loongarch_iocsrrd_h",
+    "llvm.loongarch.iocsrrd.w" => "__builtin_loongarch_iocsrrd_w",
+    "llvm.loongarch.iocsrwr.b" => "__builtin_loongarch_iocsrwr_b",
+    "llvm.loongarch.iocsrwr.d" => "__builtin_loongarch_iocsrwr_d",
+    "llvm.loongarch.iocsrwr.h" => "__builtin_loongarch_iocsrwr_h",
+    "llvm.loongarch.iocsrwr.w" => "__builtin_loongarch_iocsrwr_w",
+    "llvm.loongarch.lddir.d" => "__builtin_loongarch_lddir_d",
+    "llvm.loongarch.ldpte.d" => "__builtin_loongarch_ldpte_d",
+    "llvm.loongarch.movfcsr2gr" => "__builtin_loongarch_movfcsr2gr",
+    "llvm.loongarch.movgr2fcsr" => "__builtin_loongarch_movgr2fcsr",
+    "llvm.loongarch.syscall" => "__builtin_loongarch_syscall",
     // mips
     "llvm.mips.absq.s.ph" => "__builtin_mips_absq_s_ph",
     "llvm.mips.absq.s.qb" => "__builtin_mips_absq_s_qb",
@@ -2954,6 +2990,8 @@ match name {
     "llvm.nvvm.barrier0.and" => "__nvvm_bar0_and",
     "llvm.nvvm.barrier0.or" => "__nvvm_bar0_or",
     "llvm.nvvm.barrier0.popc" => "__nvvm_bar0_popc",
+    "llvm.nvvm.bf2h.rn" => "__nvvm_bf2h_rn",
+    "llvm.nvvm.bf2h.rn.ftz" => "__nvvm_bf2h_rn_ftz",
     "llvm.nvvm.bitcast.d2ll" => "__nvvm_bitcast_d2ll",
     "llvm.nvvm.bitcast.f2i" => "__nvvm_bitcast_f2i",
     "llvm.nvvm.bitcast.i2f" => "__nvvm_bitcast_i2f",
@@ -3016,8 +3054,6 @@ match name {
     "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f",
     "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d",
     "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f",
-    "llvm.nvvm.ex2.approx.f16" => "__nvvm_ex2_approx_f16",
-    "llvm.nvvm.ex2.approx.f16x2" => "__nvvm_ex2_approx_f16x2",
     "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f",
     "llvm.nvvm.f2bf16.rn" => "__nvvm_f2bf16_rn",
     "llvm.nvvm.f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu",
@@ -3079,11 +3115,17 @@ match name {
     "llvm.nvvm.fma.rn.bf16x2" => "__nvvm_fma_rn_bf16x2",
     "llvm.nvvm.fma.rn.d" => "__nvvm_fma_rn_d",
     "llvm.nvvm.fma.rn.f" => "__nvvm_fma_rn_f",
-    "llvm.nvvm.fma.rn.f16" => "__nvvm_fma_rn_f16",
-    "llvm.nvvm.fma.rn.f16x2" => "__nvvm_fma_rn_f16x2",
+    "llvm.nvvm.fma.rn.ftz.bf16" => "__nvvm_fma_rn_ftz_bf16",
+    "llvm.nvvm.fma.rn.ftz.bf16x2" => "__nvvm_fma_rn_ftz_bf16x2",
     "llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f",
+    "llvm.nvvm.fma.rn.ftz.relu.bf16" => "__nvvm_fma_rn_ftz_relu_bf16",
+    "llvm.nvvm.fma.rn.ftz.relu.bf16x2" => "__nvvm_fma_rn_ftz_relu_bf16x2",
+    "llvm.nvvm.fma.rn.ftz.sat.bf16" => "__nvvm_fma_rn_ftz_sat_bf16",
+    "llvm.nvvm.fma.rn.ftz.sat.bf16x2" => "__nvvm_fma_rn_ftz_sat_bf16x2",
     "llvm.nvvm.fma.rn.relu.bf16" => "__nvvm_fma_rn_relu_bf16",
     "llvm.nvvm.fma.rn.relu.bf16x2" => "__nvvm_fma_rn_relu_bf16x2",
+    "llvm.nvvm.fma.rn.sat.bf16" => "__nvvm_fma_rn_sat_bf16",
+    "llvm.nvvm.fma.rn.sat.bf16x2" => "__nvvm_fma_rn_sat_bf16x2",
     "llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d",
     "llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f",
     "llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f",
@@ -3094,11 +3136,17 @@ match name {
     "llvm.nvvm.fmax.bf16x2" => "__nvvm_fmax_bf16x2",
     "llvm.nvvm.fmax.d" => "__nvvm_fmax_d",
     "llvm.nvvm.fmax.f" => "__nvvm_fmax_f",
-    "llvm.nvvm.fmax.f16" => "__nvvm_fmax_f16",
-    "llvm.nvvm.fmax.f16x2" => "__nvvm_fmax_f16x2",
+    "llvm.nvvm.fmax.ftz.bf16" => "__nvvm_fmax_ftz_bf16",
+    "llvm.nvvm.fmax.ftz.bf16x2" => "__nvvm_fmax_ftz_bf16x2",
     "llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f",
+    "llvm.nvvm.fmax.ftz.nan.bf16" => "__nvvm_fmax_ftz_nan_bf16",
+    "llvm.nvvm.fmax.ftz.nan.bf16x2" => "__nvvm_fmax_ftz_nan_bf16x2",
     "llvm.nvvm.fmax.ftz.nan.f" => "__nvvm_fmax_ftz_nan_f",
+    "llvm.nvvm.fmax.ftz.nan.xorsign.abs.bf16" => "__nvvm_fmax_ftz_nan_xorsign_abs_bf16",
+    "llvm.nvvm.fmax.ftz.nan.xorsign.abs.bf16x2" => "__nvvm_fmax_ftz_nan_xorsign_abs_bf16x2",
     "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f" => "__nvvm_fmax_ftz_nan_xorsign_abs_f",
+    "llvm.nvvm.fmax.ftz.xorsign.abs.bf16" => "__nvvm_fmax_ftz_xorsign_abs_bf16",
+    "llvm.nvvm.fmax.ftz.xorsign.abs.bf16x2" => "__nvvm_fmax_ftz_xorsign_abs_bf16x2",
     "llvm.nvvm.fmax.ftz.xorsign.abs.f" => "__nvvm_fmax_ftz_xorsign_abs_f",
     "llvm.nvvm.fmax.nan.bf16" => "__nvvm_fmax_nan_bf16",
     "llvm.nvvm.fmax.nan.bf16x2" => "__nvvm_fmax_nan_bf16x2",
@@ -3113,11 +3161,17 @@ match name {
     "llvm.nvvm.fmin.bf16x2" => "__nvvm_fmin_bf16x2",
     "llvm.nvvm.fmin.d" => "__nvvm_fmin_d",
     "llvm.nvvm.fmin.f" => "__nvvm_fmin_f",
-    "llvm.nvvm.fmin.f16" => "__nvvm_fmin_f16",
-    "llvm.nvvm.fmin.f16x2" => "__nvvm_fmin_f16x2",
+    "llvm.nvvm.fmin.ftz.bf16" => "__nvvm_fmin_ftz_bf16",
+    "llvm.nvvm.fmin.ftz.bf16x2" => "__nvvm_fmin_ftz_bf16x2",
     "llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f",
+    "llvm.nvvm.fmin.ftz.nan.bf16" => "__nvvm_fmin_ftz_nan_bf16",
+    "llvm.nvvm.fmin.ftz.nan.bf16x2" => "__nvvm_fmin_ftz_nan_bf16x2",
     "llvm.nvvm.fmin.ftz.nan.f" => "__nvvm_fmin_ftz_nan_f",
+    "llvm.nvvm.fmin.ftz.nan.xorsign.abs.bf16" => "__nvvm_fmin_ftz_nan_xorsign_abs_bf16",
+    "llvm.nvvm.fmin.ftz.nan.xorsign.abs.bf16x2" => "__nvvm_fmin_ftz_nan_xorsign_abs_bf16x2",
     "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f" => "__nvvm_fmin_ftz_nan_xorsign_abs_f",
+    "llvm.nvvm.fmin.ftz.xorsign.abs.bf16" => "__nvvm_fmin_ftz_xorsign_abs_bf16",
+    "llvm.nvvm.fmin.ftz.xorsign.abs.bf16x2" => "__nvvm_fmin_ftz_xorsign_abs_bf16x2",
     "llvm.nvvm.fmin.ftz.xorsign.abs.f" => "__nvvm_fmin_ftz_xorsign_abs_f",
     "llvm.nvvm.fmin.nan.bf16" => "__nvvm_fmin_nan_bf16",
     "llvm.nvvm.fmin.nan.bf16x2" => "__nvvm_fmin_nan_bf16x2",
@@ -4213,6 +4267,28 @@ match name {
     "llvm.r600.read.tgid.x" => "__builtin_r600_read_tgid_x",
     "llvm.r600.read.tgid.y" => "__builtin_r600_read_tgid_y",
     "llvm.r600.read.tgid.z" => "__builtin_r600_read_tgid_z",
+    // riscv
+    "llvm.riscv.aes32dsi" => "__builtin_riscv_aes32dsi",
+    "llvm.riscv.aes32dsmi" => "__builtin_riscv_aes32dsmi",
+    "llvm.riscv.aes32esi" => "__builtin_riscv_aes32esi",
+    "llvm.riscv.aes32esmi" => "__builtin_riscv_aes32esmi",
+    "llvm.riscv.aes64ds" => "__builtin_riscv_aes64ds",
+    "llvm.riscv.aes64dsm" => "__builtin_riscv_aes64dsm",
+    "llvm.riscv.aes64es" => "__builtin_riscv_aes64es",
+    "llvm.riscv.aes64esm" => "__builtin_riscv_aes64esm",
+    "llvm.riscv.aes64im" => "__builtin_riscv_aes64im",
+    "llvm.riscv.aes64ks1i" => "__builtin_riscv_aes64ks1i",
+    "llvm.riscv.aes64ks2" => "__builtin_riscv_aes64ks2",
+    "llvm.riscv.sha512sig0" => "__builtin_riscv_sha512sig0",
+    "llvm.riscv.sha512sig0h" => "__builtin_riscv_sha512sig0h",
+    "llvm.riscv.sha512sig0l" => "__builtin_riscv_sha512sig0l",
+    "llvm.riscv.sha512sig1" => "__builtin_riscv_sha512sig1",
+    "llvm.riscv.sha512sig1h" => "__builtin_riscv_sha512sig1h",
+    "llvm.riscv.sha512sig1l" => "__builtin_riscv_sha512sig1l",
+    "llvm.riscv.sha512sum0" => "__builtin_riscv_sha512sum0",
+    "llvm.riscv.sha512sum0r" => "__builtin_riscv_sha512sum0r",
+    "llvm.riscv.sha512sum1" => "__builtin_riscv_sha512sum1",
+    "llvm.riscv.sha512sum1r" => "__builtin_riscv_sha512sum1r",
     // s390
     "llvm.s390.efpc" => "__builtin_s390_efpc",
     "llvm.s390.etnd" => "__builtin_tx_nesting_depth",
@@ -5912,6 +5988,18 @@ match name {
     "llvm.x86.avx2.vpdpbuud.256" => "__builtin_ia32_vpdpbuud256",
     "llvm.x86.avx2.vpdpbuuds.128" => "__builtin_ia32_vpdpbuuds128",
     "llvm.x86.avx2.vpdpbuuds.256" => "__builtin_ia32_vpdpbuuds256",
+    "llvm.x86.avx2.vpdpwsud.128" => "__builtin_ia32_vpdpwsud128",
+    "llvm.x86.avx2.vpdpwsud.256" => "__builtin_ia32_vpdpwsud256",
+    "llvm.x86.avx2.vpdpwsuds.128" => "__builtin_ia32_vpdpwsuds128",
+    "llvm.x86.avx2.vpdpwsuds.256" => "__builtin_ia32_vpdpwsuds256",
+    "llvm.x86.avx2.vpdpwusd.128" => "__builtin_ia32_vpdpwusd128",
+    "llvm.x86.avx2.vpdpwusd.256" => "__builtin_ia32_vpdpwusd256",
+    "llvm.x86.avx2.vpdpwusds.128" => "__builtin_ia32_vpdpwusds128",
+    "llvm.x86.avx2.vpdpwusds.256" => "__builtin_ia32_vpdpwusds256",
+    "llvm.x86.avx2.vpdpwuud.128" => "__builtin_ia32_vpdpwuud128",
+    "llvm.x86.avx2.vpdpwuud.256" => "__builtin_ia32_vpdpwuud256",
+    "llvm.x86.avx2.vpdpwuuds.128" => "__builtin_ia32_vpdpwuuds128",
+    "llvm.x86.avx2.vpdpwuuds.256" => "__builtin_ia32_vpdpwuuds256",
     "llvm.x86.avx2.vperm2i128" => "__builtin_ia32_permti256",
     "llvm.x86.avx512.add.pd.512" => "__builtin_ia32_addpd512",
     "llvm.x86.avx512.add.ps.512" => "__builtin_ia32_addps512",
@@ -7909,6 +7997,16 @@ match name {
     "llvm.x86.vgf2p8mulb.128" => "__builtin_ia32_vgf2p8mulb_v16qi",
     "llvm.x86.vgf2p8mulb.256" => "__builtin_ia32_vgf2p8mulb_v32qi",
     "llvm.x86.vgf2p8mulb.512" => "__builtin_ia32_vgf2p8mulb_v64qi",
+    "llvm.x86.vsha512msg1" => "__builtin_ia32_vsha512msg1",
+    "llvm.x86.vsha512msg2" => "__builtin_ia32_vsha512msg2",
+    "llvm.x86.vsha512rnds2" => "__builtin_ia32_vsha512rnds2",
+    "llvm.x86.vsm3msg1" => "__builtin_ia32_vsm3msg1",
+    "llvm.x86.vsm3msg2" => "__builtin_ia32_vsm3msg2",
+    "llvm.x86.vsm3rnds2" => "__builtin_ia32_vsm3rnds2",
+    "llvm.x86.vsm4key4128" => "__builtin_ia32_vsm4key4128",
+    "llvm.x86.vsm4key4256" => "__builtin_ia32_vsm4key4256",
+    "llvm.x86.vsm4rnds4128" => "__builtin_ia32_vsm4rnds4128",
+    "llvm.x86.vsm4rnds4256" => "__builtin_ia32_vsm4rnds4256",
     "llvm.x86.wbinvd" => "__builtin_ia32_wbinvd",
     "llvm.x86.wbnoinvd" => "__builtin_ia32_wbnoinvd",
     "llvm.x86.wrfsbase.32" => "__builtin_ia32_wrfsbase32",
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
index f28348380d7..5996623bdc5 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
@@ -236,11 +236,17 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
                 let arg2 = builder.context.new_cast(None, arg2, arg2_type);
                 args = vec![new_args[0], arg2].into();
             },
+            // These builtins are sent one more argument than needed.
             "__builtin_prefetch" => {
                 let mut new_args = args.to_vec();
                 new_args.pop();
                 args = new_args.into();
             },
+            // The GCC version returns one value of the tuple through a pointer.
+            "__builtin_ia32_rdrand64_step" => {
+                let arg = builder.current_func().new_local(None, builder.ulonglong_type, "return_rdrand_arg");
+                args = vec![arg.get_address(None)].into();
+            },
             _ => (),
         }
     }
@@ -361,6 +367,19 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc,
             // builtin twice, we overwrite the return value with a dummy value.
             return_value = builder.context.new_rvalue_zero(builder.int_type);
         },
+        "__builtin_ia32_rdrand64_step" => {
+            let random_number = args[0].dereference(None).to_rvalue();
+            let success_variable = builder.current_func().new_local(None, return_value.get_type(), "success");
+            builder.llbb().add_assignment(None, success_variable, return_value);
+
+            let field1 = builder.context.new_field(None, random_number.get_type(), "random_number");
+            let field2 = builder.context.new_field(None, return_value.get_type(), "success");
+            let struct_type = builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]);
+            return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[
+                random_number,
+                success_variable.to_rvalue(),
+            ]);
+        },
         _ => (),
     }
 
@@ -613,6 +632,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
         "llvm.fshr.v8i16" => "__builtin_ia32_vpshrdv_v8hi",
         "llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd3",
         "llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss3",
+        "llvm.x86.rdrand.64" => "__builtin_ia32_rdrand64_step",
 
         // The above doc points to unknown builtins for the following, so override them:
         "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gathersiv4si",
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 68a087a1d7f..9caed459a29 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -10,9 +10,9 @@ use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::common::IntPredicate;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
-use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
+use rustc_codegen_ssa::traits::{ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
 #[cfg(feature="master")]
-use rustc_codegen_ssa::traits::MiscMethods;
+use rustc_codegen_ssa::traits::{BaseTypeMethods, MiscMethods};
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Instance, Ty};
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index ce7e31682f1..9c18fc4a0dc 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -2,6 +2,12 @@
  * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?)
  * TODO(antoyo): support #[inline] attributes.
  * TODO(antoyo): support LTO (gcc's equivalent to Full LTO is -flto -flto-partition=one — https://documentation.suse.com/sbp/all/html/SBP-GCC-10/index.html).
+ * For Thin LTO, this might be helpful:
+ * In gcc 4.6 -fwhopr was removed and became default with -flto. The non-whopr path can still be executed via -flto-partition=none.
+ *
+ * Maybe some missing optizations enabled by rustc's LTO is in there: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
+ * Like -fipa-icf (should be already enabled) and maybe -fdevirtualize-at-ltrans.
+ * TODO: disable debug info always being emitted. Perhaps this slows down things?
  *
  * TODO(antoyo): remove the patches.
  */
@@ -28,6 +34,7 @@ extern crate rustc_codegen_ssa;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
 extern crate rustc_fluent_macro;
+extern crate rustc_fs_util;
 extern crate rustc_hir;
 extern crate rustc_macros;
 extern crate rustc_metadata;
@@ -35,7 +42,8 @@ extern crate rustc_middle;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
-extern crate tempfile;
+#[macro_use]
+extern crate tracing;
 
 // This prevents duplicating functions and statics that are already part of the host rustc process.
 #[allow(unused_extern_crates)]
@@ -57,6 +65,7 @@ mod coverageinfo;
 mod debuginfo;
 mod declare;
 mod errors;
+mod gcc_util;
 mod int;
 mod intrinsic;
 mod mono_item;
@@ -64,18 +73,29 @@ mod type_;
 mod type_of;
 
 use std::any::Any;
-use std::sync::{Arc, Mutex};
-
-use crate::errors::LTONotSupported;
-use gccjit::{Context, OptimizationLevel, CType};
+use std::fmt::Debug;
+use std::sync::Arc;
+use std::sync::Mutex;
+#[cfg(not(feature="master"))]
+use std::sync::atomic::AtomicBool;
+#[cfg(not(feature="master"))]
+use std::sync::atomic::Ordering;
+
+use gccjit::{Context, OptimizationLevel};
+#[cfg(feature="master")]
+use gccjit::TargetInfo;
+#[cfg(not(feature="master"))]
+use gccjit::CType;
+use errors::LTONotSupported;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_codegen_ssa::base::codegen_crate;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use rustc_codegen_ssa::target_features::supported_target_features;
-use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::sync::IntoDynSyncSend;
+use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods};
 use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage};
 use rustc_fluent_macro::fluent_messages;
 use rustc_metadata::EncodedMetadata;
@@ -88,6 +108,9 @@ use rustc_span::Symbol;
 use rustc_span::fatal_error::FatalError;
 use tempfile::TempDir;
 
+use crate::back::lto::ModuleBuffer;
+use crate::gcc_util::target_cpu;
+
 fluent_messages! { "../messages.ftl" }
 
 pub struct PrintOnPanic<F: Fn() -> String>(pub F);
@@ -100,9 +123,47 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
     }
 }
 
+#[cfg(not(feature="master"))]
+#[derive(Debug)]
+pub struct TargetInfo {
+    supports_128bit_integers: AtomicBool,
+}
+
+#[cfg(not(feature="master"))]
+impl TargetInfo {
+    fn cpu_supports(&self, _feature: &str) -> bool {
+        false
+    }
+
+    fn supports_128bit_int(&self) -> bool {
+        self.supports_128bit_integers.load(Ordering::SeqCst)
+    }
+}
+
+#[derive(Clone)]
+pub struct LockedTargetInfo {
+    info: Arc<Mutex<IntoDynSyncSend<TargetInfo>>>,
+}
+
+impl Debug for LockedTargetInfo {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.info.lock().expect("lock").fmt(formatter)
+    }
+}
+
+impl LockedTargetInfo {
+    fn cpu_supports(&self, feature: &str) -> bool {
+        self.info.lock().expect("lock").cpu_supports(feature)
+    }
+
+    fn supports_128bit_int(&self) -> bool {
+        self.info.lock().expect("lock").supports_128bit_int()
+    }
+}
+
 #[derive(Clone)]
 pub struct GccCodegenBackend {
-    supports_128bit_integers: Arc<Mutex<bool>>,
+    target_info: LockedTargetInfo,
 }
 
 impl CodegenBackend for GccCodegenBackend {
@@ -112,24 +173,40 @@ impl CodegenBackend for GccCodegenBackend {
 
     fn init(&self, sess: &Session) {
         #[cfg(feature="master")]
+        {
+            let target_cpu = target_cpu(sess);
+
+            // Get the second TargetInfo with the correct CPU features by setting the arch.
+            let context = Context::default();
+            if target_cpu != "generic" {
+                context.add_command_line_option(&format!("-march={}", target_cpu));
+            }
+
+            **self.target_info.info.lock().expect("lock") = context.get_target_info();
+        }
+
+        #[cfg(feature="master")]
         gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
-        if sess.lto() != Lto::No {
+        if sess.lto() == Lto::Thin {
             sess.emit_warning(LTONotSupported {});
         }
 
-        let temp_dir = TempDir::new().expect("cannot create temporary directory");
-        let temp_file = temp_dir.into_path().join("result.asm");
-        let check_context = Context::default();
-        check_context.set_print_errors_to_stderr(false);
-        let _int128_ty = check_context.new_c_type(CType::UInt128t);
-        // NOTE: we cannot just call compile() as this would require other files than libgccjit.so.
-        check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str"));
-        *self.supports_128bit_integers.lock().expect("lock") = check_context.get_last_error() == Ok(None);
+        #[cfg(not(feature="master"))]
+        {
+            let temp_dir = TempDir::new().expect("cannot create temporary directory");
+            let temp_file = temp_dir.into_path().join("result.asm");
+            let check_context = Context::default();
+            check_context.set_print_errors_to_stderr(false);
+            let _int128_ty = check_context.new_c_type(CType::UInt128t);
+            // NOTE: we cannot just call compile() as this would require other files than libgccjit.so.
+            check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str"));
+            self.target_info.info.lock().expect("lock").supports_128bit_integers.store(check_context.get_last_error() == Ok(None), Ordering::SeqCst);
+        }
     }
 
     fn provide(&self, providers: &mut Providers) {
-        // FIXME(antoyo) compute list of enabled features from cli flags
-        providers.global_backend_features = |_tcx, ()| vec![];
+        providers.global_backend_features =
+            |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true)
     }
 
     fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> {
@@ -160,7 +237,7 @@ impl CodegenBackend for GccCodegenBackend {
     }
 
     fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
-        target_features(sess, allow_unstable)
+        target_features(sess, allow_unstable, &self.target_info)
     }
 }
 
@@ -168,13 +245,18 @@ impl ExtraBackendMethods for GccCodegenBackend {
     fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
         let mut mods = GccContext {
             context: Context::default(),
+            should_combine_object_files: false,
+            temp_dir: None,
         };
+
+        // TODO(antoyo): only set for x86.
+        mods.context.add_command_line_option("-masm=intel");
         unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
         mods
     }
 
     fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
-        base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock"))
+        base::compile_codegen_unit(tcx, cgu_name, self.target_info.clone())
     }
 
     fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> {
@@ -185,14 +267,6 @@ impl ExtraBackendMethods for GccCodegenBackend {
     }
 }
 
-pub struct ModuleBuffer;
-
-impl ModuleBufferMethods for ModuleBuffer {
-    fn data(&self) -> &[u8] {
-        unimplemented!();
-    }
-}
-
 pub struct ThinBuffer;
 
 impl ThinBufferMethods for ThinBuffer {
@@ -203,6 +277,9 @@ impl ThinBufferMethods for ThinBuffer {
 
 pub struct GccContext {
     context: Context<'static>,
+    should_combine_object_files: bool,
+    // Temporary directory used by LTO. We keep it here so that it's not removed before linking.
+    temp_dir: Option<TempDir>,
 }
 
 unsafe impl Send for GccContext {}
@@ -217,18 +294,8 @@ impl WriteBackendMethods for GccCodegenBackend {
     type ThinData = ();
     type ThinBuffer = ThinBuffer;
 
-    fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLtoInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
-        // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
-        // NOTE: implemented elsewhere.
-        // TODO(antoyo): what is implemented elsewhere ^ ?
-        let module =
-            match modules.remove(0) {
-                FatLtoInput::InMemory(module) => module,
-                FatLtoInput::Serialized { .. } => {
-                    unimplemented!();
-                }
-            };
-        Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
+    fn run_fat_lto(cgcx: &CodegenContext<Self>, modules: Vec<FatLtoInput<Self>>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
+        back::lto::run_fat(cgcx, modules, cached_modules)
     }
 
     fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
@@ -277,8 +344,19 @@ impl WriteBackendMethods for GccCodegenBackend {
 /// This is the entrypoint for a hot plugged rustc_codegen_gccjit
 #[no_mangle]
 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
+    #[cfg(feature="master")]
+    let info = {
+        // Check whether the target supports 128-bit integers.
+        let context = Context::default();
+        Arc::new(Mutex::new(IntoDynSyncSend(context.get_target_info())))
+    };
+    #[cfg(not(feature="master"))]
+    let info = Arc::new(Mutex::new(IntoDynSyncSend(TargetInfo {
+        supports_128bit_integers: AtomicBool::new(false),
+    })));
+
     Box::new(GccCodegenBackend {
-        supports_128bit_integers: Arc::new(Mutex::new(false)),
+        target_info: LockedTargetInfo { info },
     })
 }
 
@@ -297,22 +375,7 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
     }
 }
 
-fn handle_native(name: &str) -> &str {
-    if name != "native" {
-        return name;
-    }
-
-    unimplemented!();
-}
-
-pub fn target_cpu(sess: &Session) -> &str {
-    match sess.opts.cg.target_cpu {
-        Some(ref name) => handle_native(name),
-        None => handle_native(sess.target.cpu.as_ref()),
-    }
-}
-
-pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
+pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &LockedTargetInfo) -> Vec<Symbol> {
     supported_target_features(sess)
         .iter()
         .filter_map(
@@ -321,26 +384,13 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
             },
         )
         .filter(|_feature| {
-            // TODO(antoyo): implement a way to get enabled feature in libgccjit.
-            // Probably using the equivalent of __builtin_cpu_supports.
-            // TODO(antoyo): maybe use whatever outputs the following command:
-            // gcc -march=native -Q --help=target
-            #[cfg(feature="master")]
-            {
-                // NOTE: the CPU in the CI doesn't support sse4a, so disable it to make the stdarch tests pass in the CI.
-                (_feature.contains("sse") || _feature.contains("avx")) && !_feature.contains("avx512") && !_feature.contains("sse4a")
-            }
-            #[cfg(not(feature="master"))]
-            {
-                false
-            }
+            target_info.cpu_supports(_feature)
             /*
                adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma,
                avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
                bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
                sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
              */
-            //false
         })
         .map(|feature| Symbol::intern(feature))
         .collect()
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index cc467801beb..c2eab295acd 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -182,6 +182,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
     /// of that field's type - this is useful for taking the address of
     /// that field and ensuring the struct has the right alignment.
     fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        use crate::rustc_middle::ty::layout::FnAbiOf;
         // This must produce the same result for `repr(transparent)` wrappers as for the inner type!
         // In other words, this should generally not look at the type at all, but only at the
         // layout.
@@ -191,7 +192,14 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
             if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
                 return ty;
             }
-            let ty = self.scalar_gcc_type_at(cx, scalar, Size::ZERO);
+            let ty =
+                match *self.ty.kind() {
+                    // NOTE: we cannot remove this match like in the LLVM codegen because the call
+                    // to fn_ptr_backend_type handle the on-stack attribute.
+                    // TODO(antoyo): find a less hackish way to hande the on-stack attribute.
+                    ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())),
+                    _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
+                };
             cx.scalar_types.borrow_mut().insert(self.ty, ty);
             return ty;
         }
diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh
index b462e5d156b..e4cbd6fbcaf 100755
--- a/compiler/rustc_codegen_gcc/test.sh
+++ b/compiler/rustc_codegen_gcc/test.sh
@@ -3,6 +3,7 @@
 # TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed?
 
 set -e
+#set -x
 
 if [ -f ./gcc_path ]; then
     export GCC_PATH=$(cat gcc_path)
@@ -219,6 +220,7 @@ change-id = 115898
 [rust]
 codegen-backends = []
 deny-warnings = false
+verbose-tests = true
 
 [build]
 cargo = "$(rustup which cargo)"
@@ -345,15 +347,19 @@ function test_rustc() {
 
     git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
 
-    rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,*lto*.rs,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true
-    rm tests/ui/mir/mir_heavy_promoted.rs # this tests is oom-killed in the CI.
-    for test in $(rg --files-with-matches "thread|lto" tests/ui); do
+    rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true
+    rm tests/ui/mir/mir_heavy_promoted.rs # this test is oom-killed in the CI.
+    # Tests generating errors.
+    rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs tests/ui/consts/issue-94675.rs
+    for test in $(rg --files-with-matches "thread" tests/ui); do
       rm $test
     done
-    git checkout tests/ui/lto/auxiliary/dylib.rs
     git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs
     git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs
     git checkout tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs
+    git checkout tests/ui/imports/ambiguous-1.rs
+    git checkout tests/ui/imports/ambiguous-4-extern.rs
+    git checkout tests/ui/entry-point/auxiliary/bad_main_functions.rs
 
     RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot"
 
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
index 25041d93e74..44297e12779 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -3,7 +3,8 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
index e7443c8dbe5..ce816927123 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -3,7 +3,8 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
index 49b28d98f2f..afd0eed8200 100644
--- a/compiler/rustc_codegen_gcc/tests/run/array.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/array.rs
@@ -7,7 +7,8 @@
 //     5
 //     10
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 38c1eac7adf..507b65ca049 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -124,7 +124,7 @@ fn main() {
     // check const (ATT syntax)
     let mut x: u64 = 42;
     unsafe {
-        asm!("add {}, {}",
+        asm!("add ${}, {}",
             const 1,
             inout(reg) x,
             options(att_syntax)
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
index 427c1a25033..5b0db2da294 100644
--- a/compiler/rustc_codegen_gcc/tests/run/assign.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -5,8 +5,8 @@
 //     7 8
 //     10
 
-#![allow(unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+#![allow(internal_features, unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
index 8daa681abf7..4ce528f8680 100644
--- a/compiler/rustc_codegen_gcc/tests/run/closure.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs
@@ -9,7 +9,8 @@
 //     Both args: 11
 
 #![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics,
-    unboxed_closures)]
+    unboxed_closures, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
index b7a13081dea..1b3ae6dc004 100644
--- a/compiler/rustc_codegen_gcc/tests/run/condition.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs
@@ -5,7 +5,8 @@
 //   stdout: true
 //     1
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
index c02cfd2a85f..2d78ef12aa7 100644
--- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
@@ -4,6 +4,7 @@
 //   status: 0
 
 #![feature(auto_traits, lang_items, no_core, start)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
index 956e53dd4aa..bf1cbeef302 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs
@@ -4,6 +4,7 @@
 //   status: 2
 
 #![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
index eeab3520951..be7a233efda 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
@@ -4,6 +4,7 @@
 //   status: 1
 
 #![feature(auto_traits, lang_items, no_core, start)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
index 8a196f774c8..96030359772 100644
--- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
@@ -4,7 +4,8 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/gep.rs b/compiler/rustc_codegen_gcc/tests/run/gep.rs
new file mode 100644
index 00000000000..c3d1672cff5
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/gep.rs
@@ -0,0 +1,10 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+
+fn main() {
+    let mut value = (1, 1);
+    let ptr = &mut value as *mut (i32, i32);
+    println!("{:?}", ptr.wrapping_offset(10));
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
index c3fcb3c0a2a..08fa087fccd 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
@@ -4,8 +4,8 @@
 //   stdout: Success
 //   status: signal
 
-#![allow(unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![allow(internal_features, unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
index 2a2ea8b8bf0..194e55a3dea 100644
--- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -7,8 +7,8 @@
 //     6
 //     11
 
-#![allow(unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+#![allow(internal_features, unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
index 67b9f241dbb..2d781670873 100644
--- a/compiler/rustc_codegen_gcc/tests/run/operations.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -5,8 +5,8 @@
 //     39
 //     10
 
-#![allow(unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)]
+#![allow(internal_features, unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
index da8a8295d56..09d77abe27c 100644
--- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
@@ -4,7 +4,8 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
index 6fa10dca06f..8d40deb8c85 100644
--- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
@@ -7,6 +7,7 @@
 //     42
 
 #![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
index 96f1c4792e5..1262c86c810 100644
--- a/compiler/rustc_codegen_gcc/tests/run/slice.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs
@@ -4,7 +4,8 @@
 //   status: 0
 //   stdout: 5
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index 19201f1df26..0b933754c29 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -9,7 +9,8 @@
 //      12
 //      1
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
index 6c8884855ac..d6455667400 100644
--- a/compiler/rustc_codegen_gcc/tests/run/structs.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs
@@ -6,6 +6,7 @@
 //     2
 
 #![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
index 0b670bf2674..8a7d85ae867 100644
--- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
@@ -5,6 +5,7 @@
 //   stdout: 3
 
 #![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![allow(internal_features)]
 
 #![no_std]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py
index 83abe145e64..90fb7bfad27 100644
--- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py
+++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py
@@ -46,10 +46,10 @@ def convert_to_string(content):
 
 
 def extract_instrinsics_from_llvm(llvm_path, intrinsics):
-    p = subprocess.Popen(
-        ["llvm-tblgen", "llvm/IR/Intrinsics.td"],
-        cwd=os.path.join(llvm_path, "llvm/include"),
-        stdout=subprocess.PIPE)
+    command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"]
+    cwd = os.path.join(llvm_path, "llvm/include")
+    print("=> Running command `{}` from `{}`".format(command, cwd))
+    p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE)
     output, err = p.communicate()
     lines = convert_to_string(output).splitlines()
     pos = 0
diff --git a/compiler/rustc_codegen_gcc/y.sh b/compiler/rustc_codegen_gcc/y.sh
new file mode 100755
index 00000000000..188109743e3
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/y.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -e
+echo "[BUILD] build system" 1>&2
+cd build_system
+cargo build --release
+cd ..
+./build_system/target/release/y $@
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index ed938761694..11874898a5a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -335,12 +335,20 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
 
     // This is actually a function pointer, so wrap it in pointer DI.
     let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
+    let (size, align) = match fn_ty.kind() {
+        ty::FnDef(..) => (0, 1),
+        ty::FnPtr(..) => (
+            cx.tcx.data_layout.pointer_size.bits(),
+            cx.tcx.data_layout.pointer_align.abi.bits() as u32,
+        ),
+        _ => unreachable!(),
+    };
     let di_node = unsafe {
         llvm::LLVMRustDIBuilderCreatePointerType(
             DIB(cx),
             fn_di_node,
-            cx.tcx.data_layout.pointer_size.bits(),
-            cx.tcx.data_layout.pointer_align.abi.bits() as u32,
+            size,
+            align,
             0, // Ignore DWARF address space.
             name.as_ptr().cast(),
             name.len(),
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 6f7d7482aea..66482667336 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -168,8 +168,6 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time
 
 codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
 
-codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
-
 codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
     .note = {$output}
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index c4a0f6291e7..28a51711b93 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2964,31 +2964,23 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro
     }
 }
 
-/// When using the linker flavors opting in to `lld`, or the unstable `-Zgcc-ld=lld` flag, add the
-/// necessary paths and arguments to invoke it:
+/// When using the linker flavors opting in to `lld`, add the necessary paths and arguments to
+/// invoke it:
 /// - when the self-contained linker flag is active: the build of `lld` distributed with rustc,
 /// - or any `lld` available to `cc`.
 fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    let unstable_use_lld = sess.opts.unstable_opts.gcc_ld.is_some();
-    debug!("add_lld_args requested, flavor: '{flavor:?}', `-Zgcc-ld=lld`: {unstable_use_lld}");
-
-    // Sanity check: using the old unstable `-Zgcc-ld=lld` option requires a `cc`-using flavor.
-    let flavor_uses_cc = flavor.uses_cc();
-    if unstable_use_lld && !flavor_uses_cc {
-        sess.emit_fatal(errors::OptionGccOnly);
-    }
+    debug!("add_lld_args requested, flavor: '{flavor:?}'");
 
     // If the flavor doesn't use a C/C++ compiler to invoke the linker, or doesn't opt in to `lld`,
     // we don't need to do anything.
-    let use_lld = flavor.uses_lld() || unstable_use_lld;
-    if !flavor_uses_cc || !use_lld {
+    if !(flavor.uses_cc() && flavor.uses_lld()) {
         return;
     }
 
     // 1. Implement the "self-contained" part of this feature by adding rustc distribution
-    //    directories to the tool's search path.
-    let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld;
-    if self_contained_linker {
+    // directories to the tool's search path:
+    // - if the self-contained linker is enabled on the CLI.
+    if sess.opts.cg.link_self_contained.is_linker_enabled() {
         for path in sess.get_tools_search_paths(false) {
             cmd.arg({
                 let mut arg = OsString::from("-B");
@@ -2999,7 +2991,7 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     }
 
     // 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of
-    //    `lld` as the linker.
+    // `lld` as the linker.
     cmd.arg("-fuse-ld=lld");
 
     if !flavor.is_gnu() {
@@ -3012,13 +3004,13 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         // shown in issue #101653 and the discussion in PR #101792.
         //
         // It could be required in some cases of cross-compiling with
-        // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+        // LLD, but this is generally unspecified, and we don't know
         // which specific versions of clang, macOS SDK, host and target OS
         // combinations impact us here.
         //
         // So we do a simple first-approximation until we know more of what the
         // Apple targets require (and which would be handled prior to hitting this
-        // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+        // LLD codepath anyway), but the expectation is that until then
         // this should be manually passed if needed. We specify the target when
         // targeting a different linker flavor on macOS, and that's also always
         // the case when targeting WASM.
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index ebf04e7a399..60346228625 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -1,8 +1,7 @@
 use pathdiff::diff_paths;
 use rustc_data_structures::fx::FxHashSet;
-use std::env;
+use rustc_fs_util::try_canonicalize;
 use std::ffi::OsString;
-use std::fs;
 use std::path::{Path, PathBuf};
 
 pub struct RPathConfig<'a> {
@@ -82,12 +81,11 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> OsS
     // Mac doesn't appear to support $ORIGIN
     let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
 
-    let cwd = env::current_dir().unwrap();
-    let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib));
-    lib.pop(); // strip filename
-    let mut output = cwd.join(&config.out_filename);
-    output.pop(); // strip filename
-    let output = fs::canonicalize(&output).unwrap_or(output);
+    // Strip filenames
+    let lib = lib.parent().unwrap();
+    let output = config.out_filename.parent().unwrap();
+    let lib = try_canonicalize(lib).unwrap();
+    let output = try_canonicalize(output).unwrap();
     let relative = path_relative_from(&lib, &output)
         .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}"));
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 14311ec08fd..39b2fa37fbf 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -490,10 +490,6 @@ pub struct RlibArchiveBuildFailure {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa_option_gcc_only)]
-pub struct OptionGccOnly;
-
-#[derive(Diagnostic)]
 pub enum ExtractBundledLibsError<'a> {
     #[diag(codegen_ssa_extract_bundled_libs_open_file)]
     OpenFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index f6186a290f8..b4728ac2aa6 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 7fda2d5fadf..62e997e5cfa 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -8,7 +8,7 @@ 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, Location, TerminatorKind};
+use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 
 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -67,21 +67,6 @@ enum LocalKind {
     SSA(DefLocation),
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
-enum DefLocation {
-    Argument,
-    Body(Location),
-}
-
-impl DefLocation {
-    fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool {
-        match self {
-            DefLocation::Argument => true,
-            DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
-        }
-    }
-}
-
 struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     fx: &'mir FunctionCx<'a, 'tcx, Bx>,
     dominators: &'mir Dominators<mir::BasicBlock>,
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index b9f88cf6352..b9557eaf6ab 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -311,6 +311,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
     {
         use rustc_type_ir::sty::TyKind::*;
+
+        fn adjust_nan<
+            'mir,
+            'tcx: 'mir,
+            M: Machine<'mir, 'tcx>,
+            F1: rustc_apfloat::Float + FloatConvert<F2>,
+            F2: rustc_apfloat::Float,
+        >(
+            ecx: &InterpCx<'mir, 'tcx, M>,
+            f1: F1,
+            f2: F2,
+        ) -> F2 {
+            if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 }
+        }
+
         match *dest_ty.kind() {
             // float -> uint
             Uint(t) => {
@@ -330,9 +345,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 Scalar::from_int(v, size)
             }
             // float -> f32
-            Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value),
+            Float(FloatTy::F32) => {
+                Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value))
+            }
             // float -> f64
-            Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
+            Float(FloatTy::F64) => {
+                Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value))
+            }
             // That's it.
             _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty),
         }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 2c6a4de456d..1891d286a3c 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -500,6 +500,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         b: &ImmTy<'tcx, M::Provenance>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
+        assert_eq!(a.layout.ty, b.layout.ty);
+        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`.
         // First, check x % y != 0 (or if that computation overflows).
@@ -522,7 +525,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         l: &ImmTy<'tcx, M::Provenance>,
         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));
+
         let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?;
         Ok(if overflowed {
             let size = l.layout.size;
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index aaa674a598f..b615ced6c76 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -6,6 +6,7 @@ use std::borrow::{Borrow, Cow};
 use std::fmt::Debug;
 use std::hash::Hash;
 
+use rustc_apfloat::{Float, FloatConvert};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir;
 use rustc_middle::ty::layout::TyAndLayout;
@@ -240,6 +241,16 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
         right: &ImmTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>;
 
+    /// Generate the NaN returned by a float operation, given the list of inputs.
+    /// (This is all inputs, not just NaN inputs!)
+    fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(
+        _ecx: &InterpCx<'mir, 'tcx, Self>,
+        _inputs: &[F1],
+    ) -> F2 {
+        // By default we always return the preferred NaN.
+        F2::NAN
+    }
+
     /// Called before writing the specified `local` of the `frame`.
     /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index b084864f3a7..53e1756d897 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -1,4 +1,4 @@
-use rustc_apfloat::Float;
+use rustc_apfloat::{Float, FloatConvert};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::ty::layout::TyAndLayout;
@@ -104,7 +104,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         (ImmTy::from_bool(res, *self.tcx), false)
     }
 
-    fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>(
+    fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>(
         &self,
         bin_op: mir::BinOp,
         layout: TyAndLayout<'tcx>,
@@ -113,6 +113,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> (ImmTy<'tcx, M::Provenance>, bool) {
         use rustc_middle::mir::BinOp::*;
 
+        // Performs appropriate non-deterministic adjustments of NaN results.
+        let adjust_nan = |f: F| -> F {
+            if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f }
+        };
+
         let val = match bin_op {
             Eq => ImmTy::from_bool(l == r, *self.tcx),
             Ne => ImmTy::from_bool(l != r, *self.tcx),
@@ -120,11 +125,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Le => ImmTy::from_bool(l <= r, *self.tcx),
             Gt => ImmTy::from_bool(l > r, *self.tcx),
             Ge => ImmTy::from_bool(l >= r, *self.tcx),
-            Add => ImmTy::from_scalar((l + r).value.into(), layout),
-            Sub => ImmTy::from_scalar((l - r).value.into(), layout),
-            Mul => ImmTy::from_scalar((l * r).value.into(), layout),
-            Div => ImmTy::from_scalar((l / r).value.into(), layout),
-            Rem => ImmTy::from_scalar((l % r).value.into(), layout),
+            Add => ImmTy::from_scalar(adjust_nan((l + r).value).into(), layout),
+            Sub => ImmTy::from_scalar(adjust_nan((l - r).value).into(), layout),
+            Mul => ImmTy::from_scalar(adjust_nan((l * r).value).into(), layout),
+            Div => ImmTy::from_scalar(adjust_nan((l / r).value).into(), layout),
+            Rem => ImmTy::from_scalar(adjust_nan((l % r).value).into(), layout),
             _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
         };
         (val, false)
@@ -456,6 +461,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 Ok((ImmTy::from_bool(res, *self.tcx), false))
             }
             ty::Float(fty) => {
+                // No NaN adjustment here, `-` is a bitwise operation!
                 let res = match (un_op, fty) {
                     (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
                     (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index 2e0643afb39..8642dfccd78 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -21,10 +21,18 @@ where
     };
 
     let ty = place.ty(local_decls, tcx).ty;
+    let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {});
     match tcx.layout_of(param_env.and(ty)) {
-        Ok(layout) if layout.align.abi <= pack => {
+        Ok(layout)
+            if layout.align.abi <= pack
+                && (layout.is_sized()
+                    || matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) =>
+        {
             // If the packed alignment is greater or equal to the field alignment, the type won't be
             // further disaligned.
+            // However we need to ensure the field is sized; for unsized fields, `layout.align` is
+            // just an approximation -- except when the unsized tail is a slice, where the alignment
+            // is fully determined by the type.
             debug!(
                 "is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
                 place,
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 4075481e561..5dd414cfd41 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -26,7 +26,42 @@ rustc_index::newtype_index! {
     struct PreorderIndex {}
 }
 
-pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
+#[derive(Clone, Debug)]
+pub struct Dominators<Node: Idx> {
+    kind: Kind<Node>,
+}
+
+#[derive(Clone, Debug)]
+enum Kind<Node: Idx> {
+    /// A representation optimized for a small path graphs.
+    Path,
+    General(Inner<Node>),
+}
+
+pub fn dominators<G: ControlFlowGraph>(g: &G) -> Dominators<G::Node> {
+    // We often encounter MIR bodies with 1 or 2 basic blocks. Special case the dominators
+    // computation and representation for those cases.
+    if is_small_path_graph(g) {
+        Dominators { kind: Kind::Path }
+    } else {
+        Dominators { kind: Kind::General(dominators_impl(g)) }
+    }
+}
+
+fn is_small_path_graph<G: ControlFlowGraph>(g: &G) -> bool {
+    if g.start_node().index() != 0 {
+        return false;
+    }
+    if g.num_nodes() == 1 {
+        return true;
+    }
+    if g.num_nodes() == 2 {
+        return g.successors(g.start_node()).any(|n| n.index() == 1);
+    }
+    false
+}
+
+fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
     // compute the post order index (rank) for each node
     let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
 
@@ -245,7 +280,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
 
     let time = compute_access_time(start_node, &immediate_dominators);
 
-    Dominators { start_node, post_order_rank, immediate_dominators, time }
+    Inner { post_order_rank, immediate_dominators, time }
 }
 
 /// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -310,12 +345,11 @@ fn compress(
 
 /// Tracks the list of dominators for each node.
 #[derive(Clone, Debug)]
-pub struct Dominators<N: Idx> {
-    start_node: N,
+struct Inner<N: Idx> {
     post_order_rank: IndexVec<N, usize>,
     // Even though we track only the immediate dominator of each node, it's
     // possible to get its full list of dominators by looking up the dominator
-    // of each dominator. (See the `impl Iterator for Iter` definition).
+    // of each dominator.
     immediate_dominators: IndexVec<N, Option<N>>,
     time: IndexVec<N, Time>,
 }
@@ -323,19 +357,24 @@ pub struct Dominators<N: Idx> {
 impl<Node: Idx> Dominators<Node> {
     /// Returns true if node is reachable from the start node.
     pub fn is_reachable(&self, node: Node) -> bool {
-        node == self.start_node || self.immediate_dominators[node].is_some()
+        match &self.kind {
+            Kind::Path => true,
+            Kind::General(g) => g.time[node].start != 0,
+        }
     }
 
     /// Returns the immediate dominator of node, if any.
     pub fn immediate_dominator(&self, node: Node) -> Option<Node> {
-        self.immediate_dominators[node]
-    }
-
-    /// Provides an iterator over each dominator up the CFG, for the given Node.
-    /// See the `impl Iterator for Iter` definition to understand how this works.
-    pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
-        assert!(self.is_reachable(node), "node {node:?} is not reachable");
-        Iter { dom_tree: self, node: Some(node) }
+        match &self.kind {
+            Kind::Path => {
+                if 0 < node.index() {
+                    Some(Node::new(node.index() - 1))
+                } else {
+                    None
+                }
+            }
+            Kind::General(g) => g.immediate_dominators[node],
+        }
     }
 
     /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
@@ -343,7 +382,10 @@ impl<Node: Idx> Dominators<Node> {
     /// of two unrelated nodes will also be consistent, but otherwise the order has no
     /// meaning.) This method cannot be used to determine if either Node dominates the other.
     pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
-        self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs])
+        match &self.kind {
+            Kind::Path => lhs.index().cmp(&rhs.index()),
+            Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]),
+        }
     }
 
     /// Returns true if `a` dominates `b`.
@@ -352,27 +394,14 @@ impl<Node: Idx> Dominators<Node> {
     ///
     /// Panics if `b` is unreachable.
     pub fn dominates(&self, a: Node, b: Node) -> bool {
-        let a = self.time[a];
-        let b = self.time[b];
-        assert!(b.start != 0, "node {b:?} is not reachable");
-        a.start <= b.start && b.finish <= a.finish
-    }
-}
-
-pub struct Iter<'dom, Node: Idx> {
-    dom_tree: &'dom Dominators<Node>,
-    node: Option<Node>,
-}
-
-impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
-    type Item = Node;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let Some(node) = self.node {
-            self.node = self.dom_tree.immediate_dominator(node);
-            Some(node)
-        } else {
-            None
+        match &self.kind {
+            Kind::Path => a.index() <= b.index(),
+            Kind::General(g) => {
+                let a = g.time[a];
+                let b = g.time[b];
+                assert!(b.start != 0, "node {b:?} is not reachable");
+                a.start <= b.start && b.finish <= a.finish
+            }
         }
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
index 5472bb8087e..39725ba4301 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
@@ -6,12 +6,11 @@ use super::super::tests::TestGraph;
 fn diamond() {
     let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
 
-    let dominators = dominators(&graph);
-    let immediate_dominators = &dominators.immediate_dominators;
-    assert_eq!(immediate_dominators[0], None);
-    assert_eq!(immediate_dominators[1], Some(0));
-    assert_eq!(immediate_dominators[2], Some(0));
-    assert_eq!(immediate_dominators[3], Some(0));
+    let d = dominators(&graph);
+    assert_eq!(d.immediate_dominator(0), None);
+    assert_eq!(d.immediate_dominator(1), Some(0));
+    assert_eq!(d.immediate_dominator(2), Some(0));
+    assert_eq!(d.immediate_dominator(3), Some(0));
 }
 
 #[test]
@@ -22,15 +21,14 @@ fn paper() {
         &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), (2, 1)],
     );
 
-    let dominators = dominators(&graph);
-    let immediate_dominators = &dominators.immediate_dominators;
-    assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph
-    assert_eq!(immediate_dominators[1], Some(6));
-    assert_eq!(immediate_dominators[2], Some(6));
-    assert_eq!(immediate_dominators[3], Some(6));
-    assert_eq!(immediate_dominators[4], Some(6));
-    assert_eq!(immediate_dominators[5], Some(6));
-    assert_eq!(immediate_dominators[6], None);
+    let d = dominators(&graph);
+    assert_eq!(d.immediate_dominator(0), None); // <-- note that 0 is not in graph
+    assert_eq!(d.immediate_dominator(1), Some(6));
+    assert_eq!(d.immediate_dominator(2), Some(6));
+    assert_eq!(d.immediate_dominator(3), Some(6));
+    assert_eq!(d.immediate_dominator(4), Some(6));
+    assert_eq!(d.immediate_dominator(5), Some(6));
+    assert_eq!(d.immediate_dominator(6), None);
 }
 
 #[test]
@@ -47,11 +45,11 @@ fn paper_slt() {
 #[test]
 fn immediate_dominator() {
     let graph = TestGraph::new(1, &[(1, 2), (2, 3)]);
-    let dominators = dominators(&graph);
-    assert_eq!(dominators.immediate_dominator(0), None);
-    assert_eq!(dominators.immediate_dominator(1), None);
-    assert_eq!(dominators.immediate_dominator(2), Some(1));
-    assert_eq!(dominators.immediate_dominator(3), Some(2));
+    let d = dominators(&graph);
+    assert_eq!(d.immediate_dominator(0), None);
+    assert_eq!(d.immediate_dominator(1), None);
+    assert_eq!(d.immediate_dominator(2), Some(1));
+    assert_eq!(d.immediate_dominator(3), Some(2));
 }
 
 #[test]
@@ -75,8 +73,7 @@ fn transitive_dominator() {
         ],
     );
 
-    let dom_tree = dominators(&graph);
-    let immediate_dominators = &dom_tree.immediate_dominators;
-    assert_eq!(immediate_dominators[2], Some(0));
-    assert_eq!(immediate_dominators[3], Some(0)); // This used to return Some(1).
+    let d = dominators(&graph);
+    assert_eq!(d.immediate_dominator(2), Some(0));
+    assert_eq!(d.immediate_dominator(3), Some(0)); // This used to return Some(1).
 }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 65c7aed3f10..17556c45296 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -5,6 +5,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(lazy_cell)]
 #![feature(decl_macro)]
 #![feature(panic_update_hook)]
@@ -1287,17 +1290,21 @@ pub fn ice_path() -> &'static Option<PathBuf> {
         if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
             return None;
         }
-        if let Ok("0") = std::env::var("RUST_BACKTRACE").as_deref() {
+        if let Some(s) = std::env::var_os("RUST_BACKTRACE") && s == "0" {
             return None;
         }
-        let mut path = match std::env::var("RUSTC_ICE").as_deref() {
-            // Explicitly opting out of writing ICEs to disk.
-            Ok("0") => return None,
-            Ok(s) => PathBuf::from(s),
-            Err(_) => std::env::current_dir().unwrap_or_default(),
+        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;
+                }
+                PathBuf::from(s)
+            }
+            None => std::env::current_dir().unwrap_or_default(),
         };
         let now: OffsetDateTime = SystemTime::now().into();
-        let file_now = now.format(&Rfc3339).unwrap_or(String::new());
+        let file_now = now.format(&Rfc3339).unwrap_or_default();
         let pid = std::process::id();
         path.push(format!("rustc-ice-{file_now}-{pid}.txt"));
         Some(path)
@@ -1322,7 +1329,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
     // by the user. Compiler developers and other rustc users can
     // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
     // (e.g. `RUST_BACKTRACE=1`)
-    if std::env::var("RUST_BACKTRACE").is_err() {
+    if std::env::var_os("RUST_BACKTRACE").is_none() {
         std::env::set_var("RUST_BACKTRACE", "full");
     }
 
@@ -1411,12 +1418,11 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
 
     static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
-    let file = if let Some(path) = ice_path().as_ref() {
+    let file = if let Some(path) = ice_path() {
         // Create the ICE dump target file.
         match crate::fs::File::options().create(true).append(true).open(&path) {
             Ok(mut file) => {
-                handler
-                    .emit_note(session_diagnostics::IcePath { path: path.display().to_string() });
+                handler.emit_note(session_diagnostics::IcePath { path: path.clone() });
                 if FIRST_PANIC.swap(false, Ordering::SeqCst) {
                     let _ = write!(file, "\n\nrustc version: {version}\nplatform: {triple}");
                 }
@@ -1425,10 +1431,10 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
             Err(err) => {
                 // The path ICE couldn't be written to disk, provide feedback to the user as to why.
                 handler.emit_warning(session_diagnostics::IcePathError {
-                    path: path.display().to_string(),
+                    path: path.clone(),
                     error: err.to_string(),
-                    env_var: std::env::var("RUSTC_ICE")
-                        .ok()
+                    env_var: std::env::var_os("RUSTC_ICE")
+                        .map(PathBuf::from)
                         .map(|env_var| session_diagnostics::IcePathErrorEnv { env_var }),
                 });
                 handler.emit_note(session_diagnostics::IceVersion { version, triple });
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
index 5eb587c54d9..442989f8de8 100644
--- a/compiler/rustc_driver_impl/src/session_diagnostics.rs
+++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs
@@ -52,13 +52,13 @@ pub(crate) struct IceVersion<'a> {
 #[derive(Diagnostic)]
 #[diag(driver_impl_ice_path)]
 pub(crate) struct IcePath {
-    pub path: String,
+    pub path: std::path::PathBuf,
 }
 
 #[derive(Diagnostic)]
 #[diag(driver_impl_ice_path_error)]
 pub(crate) struct IcePathError {
-    pub path: String,
+    pub path: std::path::PathBuf,
     pub error: String,
     #[subdiagnostic]
     pub env_var: Option<IcePathErrorEnv>,
@@ -67,7 +67,7 @@ pub(crate) struct IcePathError {
 #[derive(Subdiagnostic)]
 #[note(driver_impl_ice_path_error_env)]
 pub(crate) struct IcePathErrorEnv {
-    pub env_var: String,
+    pub env_var: std::path::PathBuf,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 665b5d6adec..63226504d37 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -3,6 +3,8 @@
 //! This module contains the code for creating and emitting diagnostics.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 8658cea137a..7ad0e799f44 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -13,17 +13,16 @@ use rustc_ast::NodeId;
 use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
 use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::{Feature, Features, State as FeatureState};
-use rustc_feature::{
-    ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
-};
+use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES};
 use rustc_parse::validate_attr;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::edition::{Edition, ALL_EDITIONS};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
+use thin_vec::ThinVec;
 
 /// A folder that strips out items that do not belong in the current configuration.
 pub struct StripUnconfigured<'a> {
@@ -37,13 +36,6 @@ pub struct StripUnconfigured<'a> {
 }
 
 pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
-    fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
-        sess.emit_err(FeatureRemoved {
-            span,
-            reason: reason.map(|reason| FeatureRemovedReason { reason }),
-        });
-    }
-
     fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> {
         ACTIVE_FEATURES.iter().filter(move |feature| {
             if let Some(feature_edition) = feature.edition {
@@ -54,67 +46,49 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
         })
     }
 
-    let mut features = Features::default();
-    let mut edition_enabled_features = FxHashMap::default();
-    let crate_edition = sess.edition();
-
-    for &edition in ALL_EDITIONS {
-        if edition <= crate_edition {
-            // The `crate_edition` implies its respective umbrella feature-gate
-            // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
-            edition_enabled_features.insert(edition.feature_name(), edition);
+    fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
+        if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() {
+            list
+        } else {
+            ThinVec::new()
         }
     }
 
-    for feature in active_features_up_to(crate_edition) {
-        feature.set(&mut features, DUMMY_SP);
-        edition_enabled_features.insert(feature.name, crate_edition);
-    }
-
-    // Process the edition umbrella feature-gates first, to ensure
-    // `edition_enabled_features` is completed before it's queried.
-    for attr in krate_attrs {
-        if !attr.has_name(sym::feature) {
-            continue;
-        }
-
-        let Some(list) = attr.meta_item_list() else {
-            continue;
-        };
-
-        for mi in list {
-            if !mi.is_word() {
-                continue;
-            }
-
-            let name = mi.name_or_empty();
+    let mut features = Features::default();
 
-            let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
-            if let Some(edition) = edition {
-                if edition <= crate_edition {
-                    continue;
-                }
+    // The edition from `--edition`.
+    let crate_edition = sess.edition();
 
-                for feature in active_features_up_to(edition) {
-                    // FIXME(Manishearth) there is currently no way to set
-                    // lib features by edition
-                    feature.set(&mut features, DUMMY_SP);
-                    edition_enabled_features.insert(feature.name, edition);
+    // The maximum of (a) the edition from `--edition` and (b) any edition
+    // umbrella feature-gates declared in the code.
+    // - E.g. if `crate_edition` is 2015 but `rust_2018_preview` is present,
+    //   `feature_edition` is 2018
+    let mut features_edition = crate_edition;
+    for attr in krate_attrs {
+        for mi in feature_list(attr) {
+            if mi.is_word() {
+                let name = mi.name_or_empty();
+                let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
+                if let Some(edition) = edition && edition > features_edition {
+                    features_edition = edition;
                 }
             }
         }
     }
 
-    for attr in krate_attrs {
-        if !attr.has_name(sym::feature) {
-            continue;
-        }
-
-        let Some(list) = attr.meta_item_list() else {
-            continue;
-        };
+    // Enable edition-dependent features based on `features_edition`.
+    // - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
+    let mut edition_enabled_features = FxHashSet::default();
+    for feature in active_features_up_to(features_edition) {
+        // FIXME(Manishearth) there is currently no way to set lib features by
+        // edition.
+        edition_enabled_features.insert(feature.name);
+        feature.set(&mut features);
+    }
 
-        for mi in list {
+    // Process all features declared in the code.
+    for attr in krate_attrs {
+        for mi in feature_list(attr) {
             let name = match mi.ident() {
                 Some(ident) if mi.is_word() => ident.name,
                 Some(ident) => {
@@ -136,38 +110,59 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 }
             };
 
-            if let Some(&edition) = edition_enabled_features.get(&name) {
+            // If the declared feature is an edition umbrella feature-gate,
+            // warn if it was redundant w.r.t. `crate_edition`.
+            // - E.g. warn if `rust_2018_preview` is declared when
+            //   `crate_edition` is 2018
+            // - E.g. don't warn if `rust_2018_preview` is declared when
+            //   `crate_edition` is 2015.
+            if let Some(&edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
+                if edition <= crate_edition {
+                    sess.emit_warning(FeatureIncludedInEdition {
+                        span: mi.span(),
+                        feature: name,
+                        edition,
+                    });
+                }
+                features.set_declared_lang_feature(name, mi.span(), None);
+                continue;
+            }
+
+            // If the declared feature is edition-dependent and was already
+            // enabled due to `feature_edition`, give a warning.
+            // - E.g. warn if `test_2018_feature` is declared when
+            //   `feature_edition` is 2018 or higher.
+            if edition_enabled_features.contains(&name) {
                 sess.emit_warning(FeatureIncludedInEdition {
                     span: mi.span(),
                     feature: name,
-                    edition,
+                    edition: features_edition,
                 });
+                features.set_declared_lang_feature(name, mi.span(), None);
                 continue;
             }
 
-            if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
-                // Handled in the separate loop above.
-                continue;
-            }
-
-            let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
-            let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
-            if let Some(Feature { state, .. }) = removed.or(stable_removed) {
-                if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } =
-                    state
-                {
-                    feature_removed(sess, mi.span(), *reason);
+            // If the declared feature has been removed, issue an error.
+            if let Some(Feature { state, .. }) = REMOVED_FEATURES.iter().find(|f| name == f.name) {
+                if let FeatureState::Removed { reason } = state {
+                    sess.emit_err(FeatureRemoved {
+                        span: mi.span(),
+                        reason: reason.map(|reason| FeatureRemovedReason { reason }),
+                    });
                     continue;
                 }
             }
 
+            // If the declared feature is stable, record it.
             if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
                 let since = Some(Symbol::intern(since));
-                features.declared_lang_features.push((name, mi.span(), since));
-                features.active_features.insert(name);
+                features.set_declared_lang_feature(name, mi.span(), since);
                 continue;
             }
 
+            // If `-Z allow-features` is used and the declared feature is
+            // unstable and not also listed as one of the allowed features,
+            // issue an error.
             if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
                 if allowed.iter().all(|f| name.as_str() != f) {
                     sess.emit_err(FeatureNotAllowed { span: mi.span(), name });
@@ -175,15 +170,16 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 }
             }
 
+            // If the declared feature is unstable, record it.
             if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
-                f.set(&mut features, mi.span());
-                features.declared_lang_features.push((name, mi.span(), None));
-                features.active_features.insert(name);
+                f.set(&mut features);
+                features.set_declared_lang_feature(name, mi.span(), None);
                 continue;
             }
 
-            features.declared_lib_features.push((name, mi.span()));
-            features.active_features.insert(name);
+            // Otherwise, the feature is unknown. Record it as a lib feature.
+            // It will be checked later.
+            features.set_declared_lib_feature(name, mi.span());
         }
     }
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index a02c04ecd3e..83961647bd4 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -7,15 +7,6 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
-macro_rules! set {
-    ($field: ident) => {{
-        fn f(features: &mut Features, _: Span) {
-            features.$field = true;
-        }
-        f as fn(&mut Features, Span)
-    }};
-}
-
 #[derive(PartialEq)]
 enum FeatureStatus {
     Default,
@@ -23,16 +14,19 @@ enum FeatureStatus {
     Internal,
 }
 
-macro_rules! declare_features {
-    (__status_to_enum active) => {
+macro_rules! status_to_enum {
+    (active) => {
         FeatureStatus::Default
     };
-    (__status_to_enum incomplete) => {
+    (incomplete) => {
         FeatureStatus::Incomplete
     };
-    (__status_to_enum internal) => {
+    (internal) => {
         FeatureStatus::Internal
     };
+}
+
+macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr, $edition:expr),
     )+) => {
@@ -43,7 +37,10 @@ macro_rules! declare_features {
             &[$(
                 // (sym::$feature, $ver, $issue, $edition, set!($feature))
                 Feature {
-                    state: State::Active { set: set!($feature) },
+                    state: State::Active {
+                        // Sets this feature's corresponding bool within `features`.
+                        set: |features| features.$feature = true,
+                    },
                     name: sym::$feature,
                     since: $ver,
                     issue: to_nonzero($issue),
@@ -58,8 +55,9 @@ macro_rules! declare_features {
             pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
             /// `#![feature]` attrs for non-language (library) features.
             pub declared_lib_features: Vec<(Symbol, Span)>,
-            /// Features enabled for this crate.
-            pub active_features: FxHashSet<Symbol>,
+            /// `declared_lang_features` + `declared_lib_features`.
+            pub declared_features: FxHashSet<Symbol>,
+            /// Individual features (unstable only).
             $(
                 $(#[doc = $doc])*
                 pub $feature: bool
@@ -67,16 +65,33 @@ macro_rules! declare_features {
         }
 
         impl Features {
+            pub fn set_declared_lang_feature(
+                &mut self,
+                symbol: Symbol,
+                span: Span,
+                since: Option<Symbol>
+            ) {
+                self.declared_lang_features.push((symbol, span, since));
+                self.declared_features.insert(symbol);
+            }
+
+            pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) {
+                self.declared_lib_features.push((symbol, span));
+                self.declared_features.insert(symbol);
+            }
+
             pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) {
                 $(f(stringify!($feature), self.$feature);)+
             }
 
-            /// Is the given feature active?
-            pub fn active(&self, feature: Symbol) -> bool {
-                self.active_features.contains(&feature)
+            /// Is the given feature explicitly declared, i.e. named in a
+            /// `#![feature(...)]` within the code?
+            pub fn declared(&self, feature: Symbol) -> bool {
+                self.declared_features.contains(&feature)
             }
 
-            /// Is the given feature enabled?
+            /// Is the given feature enabled, i.e. declared or automatically
+            /// enabled due to the edition?
             ///
             /// Panics if the symbol doesn't correspond to a declared feature.
             pub fn enabled(&self, feature: Symbol) -> bool {
@@ -93,11 +108,10 @@ macro_rules! declare_features {
             pub fn incomplete(&self, feature: Symbol) -> bool {
                 match feature {
                     $(
-                        sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Incomplete,
+                        sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete,
                     )*
                     // accepted and removed features aren't in this file but are never incomplete
-                    _ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false,
-                    _ if self.declared_lib_features.iter().any(|f| f.0 == feature) => false,
+                    _ if self.declared_features.contains(&feature) => false,
                     _ => panic!("`{}` was not listed in `declare_features`", feature),
                 }
             }
@@ -108,12 +122,11 @@ macro_rules! declare_features {
             pub fn internal(&self, feature: Symbol) -> bool {
                 match feature {
                     $(
-                        sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Internal,
+                        sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
                     )*
                     // accepted and removed features aren't in this file but are never internal
                     // (a removed feature might have been internal, but it doesn't matter anymore)
-                    _ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false,
-                    _ if self.declared_lib_features.iter().any(|f| f.0 == feature) => false,
+                    _ if self.declared_features.contains(&feature) => false,
                     _ => panic!("`{}` was not listed in `declare_features`", feature),
                 }
             }
@@ -123,9 +136,9 @@ macro_rules! declare_features {
 
 impl Feature {
     /// Sets this feature in `Features`. Panics if called on a non-active feature.
-    pub fn set(&self, features: &mut Features, span: Span) {
+    pub fn set(&self, features: &mut Features) {
         match self.state {
-            State::Active { set } => set(features, span),
+            State::Active { set } => set(features),
             _ => panic!("called `set` on feature `{}` which is not `active`", self.name),
         }
     }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 69e33115922..4721bff0ec7 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -23,16 +23,15 @@ mod removed;
 #[cfg(test)]
 mod tests;
 
-use rustc_span::{edition::Edition, symbol::Symbol, Span};
+use rustc_span::{edition::Edition, symbol::Symbol};
 use std::fmt;
 use std::num::NonZeroU32;
 
 #[derive(Clone, Copy)]
 pub enum State {
     Accepted,
-    Active { set: fn(&mut Features, Span) },
+    Active { set: fn(&mut Features) },
     Removed { reason: Option<&'static str> },
-    Stabilized { reason: Option<&'static str> },
 }
 
 impl fmt::Debug for State {
@@ -41,7 +40,6 @@ impl fmt::Debug for State {
             State::Accepted { .. } => write!(f, "accepted"),
             State::Active { .. } => write!(f, "active"),
             State::Removed { .. } => write!(f, "removed"),
-            State::Stabilized { .. } => write!(f, "stabilized"),
         }
     }
 }
@@ -79,8 +77,8 @@ pub enum UnstableFeatures {
 impl UnstableFeatures {
     /// This takes into account `RUSTC_BOOTSTRAP`.
     ///
-    /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly features.
-    /// Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
+    /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly
+    /// features. Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
     pub fn from_environment(krate: Option<&str>) -> Self {
         // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
         let disable_unstable_features =
@@ -107,19 +105,17 @@ impl UnstableFeatures {
 }
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
-    if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
-        info.issue
-    } else {
-        // search in Accepted, Removed, or Stable Removed features
-        let found = ACCEPTED_FEATURES
-            .iter()
-            .chain(REMOVED_FEATURES)
-            .chain(STABLE_REMOVED_FEATURES)
-            .find(|t| t.name == feature);
-        match found {
-            Some(found) => found.issue,
-            None => panic!("feature `{feature}` is not declared anywhere"),
-        }
+    // Search in all the feature lists.
+    let found = []
+        .iter()
+        .chain(ACTIVE_FEATURES)
+        .chain(ACCEPTED_FEATURES)
+        .chain(REMOVED_FEATURES)
+        .find(|t| t.name == feature);
+
+    match found {
+        Some(found) => found.issue,
+        None => panic!("feature `{feature}` is not declared anywhere"),
     }
 }
 
@@ -152,4 +148,4 @@ pub use builtin_attrs::{
     is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
     GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
-pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
+pub use removed::REMOVED_FEATURES;
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index da18cb2a239..de15deef178 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -20,23 +20,6 @@ macro_rules! declare_features {
             ),+
         ];
     };
-
-    ($(
-        $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None),
-    )+) => {
-        /// Represents stable features which have since been removed (it was once Accepted)
-        pub const STABLE_REMOVED_FEATURES: &[Feature] = &[
-            $(
-                Feature {
-                    state: State::Stabilized { reason: None },
-                    name: sym::$feature,
-                    since: $ver,
-                    issue: to_nonzero($issue),
-                    edition: None,
-                }
-            ),+
-        ];
-    };
 }
 
 #[rustfmt::skip]
@@ -141,6 +124,11 @@ declare_features! (
     (removed, no_coverage, "CURRENT_RUSTC_VERSION", Some(84605), None, Some("renamed to `coverage_attribute`")),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+    /// Note: this feature was previously recorded in a separate
+    /// `STABLE_REMOVED` list because it, uniquely, was once stable but was
+    /// then removed. But there was no utility storing it separately, so now
+    /// it's in this list.
+    (removed, no_stack_check, "1.0.0", None, None, None),
     /// Allows using `#[on_unimplemented(..)]` on traits.
     /// (Moved to `rustc_attrs`.)
     (removed, on_unimplemented, "1.40.0", None, None, None),
@@ -208,8 +196,3 @@ declare_features! (
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
 );
-
-#[rustfmt::skip]
-declare_features! (
-    (stable_removed, no_stack_check, "1.0.0", None, None),
-);
diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs
index a01643cd67d..191fb787f70 100644
--- a/compiler/rustc_fluent_macro/src/lib.rs
+++ b/compiler/rustc_fluent_macro/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_span)]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index 5d86d895817..9cb279e3efd 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -273,6 +273,9 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 56b1fd36973..a91d9231390 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -36,7 +36,7 @@ use rustc_middle::ty::{
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{sym, BytePos, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt};
@@ -1275,8 +1275,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 return;
                             };
                             // Get the span of the generics args *including* the leading `::`.
-                            let args_span =
-                                assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
+                            // We do so by stretching args.span_ext to the left by 2. Earlier
+                            // it was done based on the end of assoc segment but that sometimes
+                            // led to impossible spans and caused issues like #116473
+                            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
                             if tcx.generics_of(adt_def.did()).count() == 0 {
                                 // FIXME(estebank): we could also verify that the arguments being
                                 // work for the `enum`, instead of just looking if it takes *any*.
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 03963925d3d..c7b3648099c 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -57,6 +57,9 @@ This API is completely unstable and subject to change.
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index e426b937542..e506c150f7d 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -56,7 +56,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // closure sooner rather than later, so first examine the expected
         // type, and see if can glean a closure kind from there.
         let (expected_sig, expected_kind) = match expected.to_option(self) {
-            Some(ty) => self.deduce_closure_signature(ty),
+            Some(ty) => {
+                self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty))
+            }
             None => (None, None),
         };
         let body = self.tcx.hir().body(closure.body);
@@ -688,8 +690,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
         });
 
+        let closure_span = self.tcx.def_span(expr_def_id);
         let ret_ty = ret_coercion.borrow().expected_ty();
-        let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
+        let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty);
 
         let get_future_output = |predicate: ty::Predicate<'tcx>, span| {
             // Search for a pending obligation like
@@ -711,8 +714,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
-        let span = self.tcx.def_span(expr_def_id);
-
         let output_ty = match *ret_ty.kind() {
             ty::Infer(ty::TyVar(ret_vid)) => {
                 self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
@@ -726,17 +727,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return None,
             _ => span_bug!(
-                span,
+                closure_span,
                 "async fn generator return type not an inference variable: {ret_ty}"
             ),
         };
 
-        let output_ty = self.normalize(span, output_ty);
+        let output_ty = self.normalize(closure_span, output_ty);
 
         // async fn that have opaque types in their return type need to redo the conversion to inference variables
         // as they fetch the still opaque version from the signature.
         let InferOk { value: output_ty, obligations } = self
-            .replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env);
+            .replace_opaque_types_with_inference_vars(
+                output_ty,
+                body_def_id,
+                closure_span,
+                self.param_env,
+            );
         self.register_predicates(obligations);
 
         Some(output_ty)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index c0332a48be3..9b7f8f80310 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -16,6 +16,7 @@ use rustc_errors::{
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
@@ -28,7 +29,7 @@ use rustc_infer::infer::TypeTrace;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, IsSuggestable, Ty};
+use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, sym, BytePos, Span};
@@ -722,6 +723,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         &mut err,
                         fn_def_id,
                         callee_ty,
+                        call_expr,
+                        None,
                         Some(mismatch_idx),
                         is_method,
                     );
@@ -826,6 +829,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 &mut err,
                 fn_def_id,
                 callee_ty,
+                call_expr,
+                Some(expected_ty),
                 Some(expected_idx.as_usize()),
                 is_method,
             );
@@ -1208,7 +1213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // Call out where the function is defined
-        self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method);
+        self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method);
 
         // And add a suggestion block for all of the parameters
         let suggestion_text = match suggestion_text {
@@ -1899,6 +1904,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut Diagnostic,
         callable_def_id: Option<DefId>,
         callee_ty: Option<Ty<'tcx>>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        expected_ty: Option<Ty<'tcx>>,
         // A specific argument should be labeled, instead of all of them
         expected_idx: Option<usize>,
         is_method: bool,
@@ -2015,6 +2022,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let param = expected_idx
                 .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx));
             let (kind, span) = if let Some(param) = param {
+                // Try to find earlier invocations of this closure to find if the type mismatch
+                // is because of inference. If we find one, point at them.
+                let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
+                let node = self.tcx
+                    .opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id))
+                    .and_then(|hir_id| self.tcx.hir().find(hir_id));
+                match node {
+                    Some(hir::Node::Item(item)) => call_finder.visit_item(item),
+                    Some(hir::Node::TraitItem(item)) => call_finder.visit_trait_item(item),
+                    Some(hir::Node::ImplItem(item)) => call_finder.visit_impl_item(item),
+                    _ => {}
+                }
+                let typeck = self.typeck_results.borrow();
+                for (rcvr, args) in call_finder.calls {
+                    if let Some(rcvr_ty) = typeck.node_type_opt(rcvr.hir_id)
+                        && let ty::Closure(call_def_id, _) = rcvr_ty.kind()
+                        && def_id == *call_def_id
+                        && let Some(idx) = expected_idx
+                        && let Some(arg) = args.get(idx)
+                        && let Some(arg_ty) = typeck.node_type_opt(arg.hir_id)
+                        && let Some(expected_ty) = expected_ty
+                        && self.can_eq(self.param_env, arg_ty, expected_ty)
+                    {
+                        let mut sp: MultiSpan = vec![arg.span].into();
+                        sp.push_span_label(
+                            arg.span,
+                            format!("expected because this argument is of type `{arg_ty}`"),
+                        );
+                        sp.push_span_label(rcvr.span, "in this closure call");
+                        err.span_note(
+                            sp,
+                            format!(
+                                "expected because the closure was earlier called with an \
+                                argument of type `{arg_ty}`",
+                            ),
+                        );
+                        break;
+                    }
+                }
+
                 ("closure parameter", param.span)
             } else {
                 ("closure", self.tcx.def_span(def_id))
@@ -2028,3 +2075,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 }
+
+struct FindClosureArg<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    calls: Vec<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+}
+
+impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
+    type NestedFilter = rustc_middle::hir::nested_filter::All;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+        if let hir::ExprKind::Call(rcvr, args) = ex.kind {
+            self.calls.push((rcvr, args));
+        }
+        hir::intravisit::walk_expr(self, ex);
+    }
+}
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 220ea194a6d..472dfe3dc4a 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -2,6 +2,9 @@
 
 #![deny(missing_docs)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 12a7ecf8133..ece61ff1252 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -365,7 +365,7 @@ impl<T: Idx> From<GrowableBitSet<T>> for BitSet<T> {
 /// All operations that involve an element will panic if the element is equal
 /// to or greater than the domain size. All operations that involve two bitsets
 /// will panic if the bitsets have differing domain sizes.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(PartialEq, Eq)]
 pub struct ChunkedBitSet<T> {
     domain_size: usize,
 
@@ -1074,6 +1074,12 @@ impl<T: Idx> fmt::Debug for BitSet<T> {
     }
 }
 
+impl<T: Idx> fmt::Debug for ChunkedBitSet<T> {
+    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
+        w.debug_list().entries(self.iter()).finish()
+    }
+}
+
 impl<T: Idx> ToString for BitSet<T> {
     fn to_string(&self) -> String {
         let mut result = String::new();
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 665297da20f..5d929394eb0 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -56,7 +56,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
         // performing trait matching (which then performs equality
         // unification).
 
-        relate::relate_args(self, a_arg, b_arg)
+        relate::relate_args_invariantly(self, a_arg, b_arg)
     }
 
     fn relate_with_variance<T: Relate<'tcx>>(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 72cfc1337e2..12dcb711820 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -59,20 +59,19 @@ use crate::traits::{
 };
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::Node;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
 use rustc_middle::ty::{
-    self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt,
+    self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
@@ -2317,113 +2316,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         bound_kind: GenericKind<'tcx>,
         sub: Region<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        // Attempt to obtain the span of the parameter so we can
-        // suggest adding an explicit lifetime bound to it.
-        let generics = self.tcx.generics_of(generic_param_scope);
-        // type_param_span is (span, has_bounds)
-        let mut is_synthetic = false;
-        let mut ast_generics = None;
-        let type_param_span = match bound_kind {
-            GenericKind::Param(ref param) => {
-                // Account for the case where `param` corresponds to `Self`,
-                // which doesn't have the expected type argument.
-                if !(generics.has_self && param.index == 0) {
-                    let type_param = generics.type_param(param, self.tcx);
-                    is_synthetic = type_param.kind.is_synthetic();
-                    type_param.def_id.as_local().map(|def_id| {
-                        // Get the `hir::Param` to verify whether it already has any bounds.
-                        // We do this to avoid suggesting code that ends up as `T: 'a'b`,
-                        // instead we suggest `T: 'a + 'b` in that case.
-                        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                        ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
-                        let bounds =
-                            ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
-                        // `sp` only covers `T`, change it so that it covers
-                        // `T:` when appropriate
-                        if let Some(span) = bounds {
-                            (span, true)
-                        } else {
-                            let sp = self.tcx.def_span(def_id);
-                            (sp.shrink_to_hi(), false)
-                        }
-                    })
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        };
-
-        let new_lt = {
-            let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char));
-            let lts_names =
-                iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
-                    .flat_map(|g| &g.params)
-                    .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
-                    .map(|p| p.name.as_str())
-                    .collect::<Vec<_>>();
-            possible
-                .find(|candidate| !lts_names.contains(&&candidate[..]))
-                .unwrap_or("'lt".to_string())
-        };
-
-        let mut add_lt_suggs: Vec<Option<_>> = vec![];
-        if is_synthetic {
-            if let Some(ast_generics) = ast_generics {
-                let named_lifetime_param_exist = ast_generics.params.iter().any(|p| {
-                    matches!(
-                        p.kind,
-                        hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
-                    )
-                });
-                if named_lifetime_param_exist && let [param, ..] = ast_generics.params
-                {
-                    add_lt_suggs.push(Some((
-                        self.tcx.def_span(param.def_id).shrink_to_lo(),
-                        format!("{new_lt}, "),
-                    )));
-                } else {
-                    add_lt_suggs
-                        .push(Some((ast_generics.span.shrink_to_hi(), format!("<{new_lt}>"))));
-                }
-            }
-        } else {
-            if let [param, ..] = &generics.params[..] && let Some(def_id) = param.def_id.as_local()
-            {
-                add_lt_suggs
-                    .push(Some((self.tcx.def_span(def_id).shrink_to_lo(), format!("{new_lt}, "))));
-            }
-        }
-
-        if let Some(ast_generics) = ast_generics {
-            for p in ast_generics.params {
-                if p.is_elided_lifetime() {
-                    if self
-                        .tcx
-                        .sess
-                        .source_map()
-                        .span_to_prev_source(p.span.shrink_to_hi())
-                        .ok()
-                        .is_some_and(|s| *s.as_bytes().last().unwrap() == b'&')
-                    {
-                        add_lt_suggs
-                            .push(Some(
-                                (
-                                    p.span.shrink_to_hi(),
-                                    if let Ok(snip) = self.tcx.sess.source_map().span_to_next_source(p.span)
-                                        && snip.starts_with(' ')
-                                    {
-                                        new_lt.to_string()
-                                    } else {
-                                        format!("{new_lt} ")
-                                    }
-                                )
-                            ));
-                    } else {
-                        add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>"))));
-                    }
-                }
-            }
+        if let Some(SubregionOrigin::CompareImplItemObligation {
+            span,
+            impl_item_def_id,
+            trait_item_def_id,
+        }) = origin
+        {
+            return self.report_extra_impl_obligation(
+                span,
+                impl_item_def_id,
+                trait_item_def_id,
+                &format!("`{bound_kind}: {sub}`"),
+            );
         }
 
         let labeled_user_string = match bound_kind {
@@ -2437,223 +2341,207 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             },
         };
 
-        if let Some(SubregionOrigin::CompareImplItemObligation {
+        let mut err = self.tcx.sess.struct_span_err_with_code(
             span,
-            impl_item_def_id,
-            trait_item_def_id,
-        }) = origin
-        {
-            return self.report_extra_impl_obligation(
-                span,
-                impl_item_def_id,
-                trait_item_def_id,
-                &format!("`{bound_kind}: {sub}`"),
-            );
+            format!("{labeled_user_string} may not live long enough"),
+            match sub.kind() {
+                ty::ReEarlyBound(_) | ty::ReFree(_) if sub.has_name() => error_code!(E0309),
+                ty::ReStatic => error_code!(E0310),
+                _ => error_code!(E0311),
+            },
+        );
+
+        '_explain: {
+            let (description, span) = match sub.kind() {
+                ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
+                    msg_span_from_named_region(self.tcx, sub, Some(span))
+                }
+                _ => (format!("lifetime `{sub}`"), Some(span)),
+            };
+            let prefix = format!("{labeled_user_string} must be valid for ");
+            label_msg_span(&mut err, &prefix, description, span, "...");
+            if let Some(origin) = origin {
+                self.note_region_origin(&mut err, &origin);
+            }
         }
 
-        fn binding_suggestion<'tcx, S: fmt::Display>(
-            err: &mut Diagnostic,
-            type_param_span: Option<(Span, bool)>,
-            bound_kind: GenericKind<'tcx>,
-            sub: S,
-            add_lt_suggs: Vec<Option<(Span, String)>>,
-        ) {
+        'suggestion: {
             let msg = "consider adding an explicit lifetime bound";
-            if let Some((sp, has_lifetimes)) = type_param_span {
-                let suggestion =
-                    if has_lifetimes { format!(" + {sub}") } else { format!(": {sub}") };
-                let mut suggestions = vec![(sp, suggestion)];
-                for add_lt_sugg in add_lt_suggs.into_iter().flatten() {
-                    suggestions.push(add_lt_sugg);
+
+            if (bound_kind, sub).has_infer_regions()
+                || (bound_kind, sub).has_placeholders()
+                || !bound_kind.is_suggestable(self.tcx, false)
+            {
+                let lt_name = sub.get_name_or_anon().to_string();
+                err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
+                break 'suggestion;
+            }
+
+            let mut generic_param_scope = generic_param_scope;
+            while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
+                generic_param_scope = self.tcx.local_parent(generic_param_scope);
+            }
+
+            // type_param_sugg_span is (span, has_bounds)
+            let (type_scope, type_param_sugg_span) = match bound_kind {
+                GenericKind::Param(ref param) => {
+                    let generics = self.tcx.generics_of(generic_param_scope);
+                    let def_id = generics.type_param(param, self.tcx).def_id.expect_local();
+                    let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
+                    // Get the `hir::Param` to verify whether it already has any bounds.
+                    // We do this to avoid suggesting code that ends up as `T: 'a'b`,
+                    // instead we suggest `T: 'a + 'b` in that case.
+                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
+                    let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
+                        Some(span) => Some((span, true)),
+                        // If `param` corresponds to `Self`, no usable suggestion span.
+                        None if generics.has_self && param.index == 0 => None,
+                        None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)),
+                    };
+                    (scope, sugg_span)
                 }
-                err.multipart_suggestion_verbose(
-                    format!("{msg}..."),
-                    suggestions,
-                    Applicability::MaybeIncorrect, // Issue #41966
-                );
-            } else {
-                let consider = format!("{msg} `{bound_kind}: {sub}`...");
-                err.help(consider);
-            }
-        }
-
-        let new_binding_suggestion =
-            |err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| {
-                let msg = "consider introducing an explicit lifetime bound";
-                if let Some((sp, has_lifetimes)) = type_param_span {
-                    let suggestion =
-                        if has_lifetimes { format!(" + {new_lt}") } else { format!(": {new_lt}") };
-                    let mut sugg =
-                        vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {new_lt}"))];
-                    for lt in add_lt_suggs.clone().into_iter().flatten() {
-                        sugg.push(lt);
-                        sugg.rotate_right(1);
-                    }
-                    // `MaybeIncorrect` due to issue #41966.
-                    err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
+                _ => (generic_param_scope, None),
+            };
+            let suggestion_scope = {
+                let lifetime_scope = match sub.kind() {
+                    ty::ReStatic => hir::def_id::CRATE_DEF_ID,
+                    _ => match self.tcx.is_suitable_region(sub) {
+                        Some(info) => info.def_id,
+                        None => generic_param_scope,
+                    },
+                };
+                match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
+                    true => type_scope,
+                    false => lifetime_scope,
                 }
             };
 
-        #[derive(Debug)]
-        enum SubOrigin<'hir> {
-            GAT(&'hir hir::Generics<'hir>),
-            Impl,
-            Trait,
-            Fn,
-            Unknown,
-        }
-        let sub_origin = 'origin: {
-            match *sub {
-                ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
-                    let node = self.tcx.hir().get_if_local(def_id).unwrap();
-                    match node {
-                        Node::GenericParam(param) => {
-                            for h in self.tcx.hir().parent_iter(param.hir_id) {
-                                break 'origin match h.1 {
-                                    Node::ImplItem(hir::ImplItem {
-                                        kind: hir::ImplItemKind::Type(..),
-                                        generics,
-                                        ..
-                                    })
-                                    | Node::TraitItem(hir::TraitItem {
-                                        kind: hir::TraitItemKind::Type(..),
-                                        generics,
-                                        ..
-                                    }) => SubOrigin::GAT(generics),
-                                    Node::ImplItem(hir::ImplItem {
-                                        kind: hir::ImplItemKind::Fn(..),
-                                        ..
-                                    })
-                                    | Node::TraitItem(hir::TraitItem {
-                                        kind: hir::TraitItemKind::Fn(..),
-                                        ..
-                                    })
-                                    | Node::Item(hir::Item {
-                                        kind: hir::ItemKind::Fn(..), ..
-                                    }) => SubOrigin::Fn,
-                                    Node::Item(hir::Item {
-                                        kind: hir::ItemKind::Trait(..),
-                                        ..
-                                    }) => SubOrigin::Trait,
-                                    Node::Item(hir::Item {
-                                        kind: hir::ItemKind::Impl(..), ..
-                                    }) => SubOrigin::Impl,
-                                    _ => continue,
-                                };
-                            }
+            let mut suggs = vec![];
+            let lt_name = self.suggest_name_region(sub, &mut suggs);
+
+            if let Some((sp, has_lifetimes)) = type_param_sugg_span
+                && suggestion_scope == type_scope
+            {
+                let suggestion =
+                    if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
+                suggs.push((sp, suggestion))
+            } else {
+                let generics = self.tcx.hir().get_generics(suggestion_scope).unwrap();
+                let pred = format!("{bound_kind}: {lt_name}");
+                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
+                suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
+            }
+
+            err.multipart_suggestion_verbose(
+                format!("{msg}"),
+                suggs,
+                Applicability::MaybeIncorrect, // Issue #41966
+            );
+        }
+
+        err
+    }
+
+    pub fn suggest_name_region(
+        &self,
+        lifetime: Region<'tcx>,
+        add_lt_suggs: &mut Vec<(Span, String)>,
+    ) -> String {
+        struct LifetimeReplaceVisitor<'tcx, 'a> {
+            tcx: TyCtxt<'tcx>,
+            needle: hir::LifetimeName,
+            new_lt: &'a str,
+            add_lt_suggs: &'a mut Vec<(Span, String)>,
+        }
+
+        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
+            fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
+                if lt.res == self.needle {
+                    let (pos, span) = lt.suggestion_position();
+                    let new_lt = &self.new_lt;
+                    let sugg = match pos {
+                        hir::LifetimeSuggestionPosition::Normal => format!("{new_lt}"),
+                        hir::LifetimeSuggestionPosition::Ampersand => format!("{new_lt} "),
+                        hir::LifetimeSuggestionPosition::ElidedPath => format!("<{new_lt}>"),
+                        hir::LifetimeSuggestionPosition::ElidedPathArgument => {
+                            format!("{new_lt}, ")
                         }
-                        _ => {}
+                        hir::LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lt}"),
+                    };
+                    self.add_lt_suggs.push((span, sugg));
+                }
+            }
+
+            fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
+                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
+                    return hir::intravisit::walk_ty(self, ty);
+                };
+                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
+                if let Some(&(_, b)) =
+                    opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
+                {
+                    let prev_needle =
+                        std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
+                    for bound in opaque_ty.bounds {
+                        self.visit_param_bound(bound);
                     }
+                    self.needle = prev_needle;
                 }
-                _ => {}
             }
-            SubOrigin::Unknown
-        };
-        debug!(?sub_origin);
-
-        let mut err = match (*sub, sub_origin) {
-            // In the case of GATs, we have to be careful. If we a type parameter `T` on an impl,
-            // but a lifetime `'a` on an associated type, then we might need to suggest adding
-            // `where T: 'a`. Importantly, this is on the GAT span, not on the `T` declaration.
-            (ty::ReEarlyBound(ty::EarlyBoundRegion { name: _, .. }), SubOrigin::GAT(generics)) => {
-                // Does the required lifetime have a nice name we can print?
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0309,
-                    "{} may not live long enough",
-                    labeled_user_string
-                );
-                let pred = format!("{bound_kind}: {sub}");
-                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
-                err.span_suggestion(
-                    generics.tail_span_for_predicate_suggestion(),
-                    "consider adding a where clause",
-                    suggestion,
-                    Applicability::MaybeIncorrect,
-                );
-                err
-            }
-            (
-                ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
-                | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
-                _,
-            ) if name != kw::UnderscoreLifetime => {
-                // Does the required lifetime have a nice name we can print?
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0309,
-                    "{} may not live long enough",
-                    labeled_user_string
-                );
-                // Explicitly use the name instead of `sub`'s `Display` impl. The `Display` impl
-                // for the bound is not suitable for suggestions when `-Zverbose` is set because it
-                // uses `Debug` output, so we handle it specially here so that suggestions are
-                // always correct.
-                binding_suggestion(&mut err, type_param_span, bound_kind, name, vec![]);
-                err
-            }
-
-            (ty::ReStatic, _) => {
-                // Does the required lifetime have a nice name we can print?
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0310,
-                    "{} may not live long enough",
-                    labeled_user_string
-                );
-                binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]);
-                err
+        }
+
+        let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(lifetime) {
+            Some(info) if !lifetime.has_name() => {
+                (info.boundregion.get_id().unwrap().expect_local(), info.def_id)
             }
+            _ => return lifetime.get_name_or_anon().to_string(),
+        };
 
-            _ => {
-                // If not, be less specific.
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0311,
-                    "{} may not live long enough",
-                    labeled_user_string
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    &format!("{labeled_user_string} must be valid for "),
-                    sub,
-                    "...",
-                    None,
-                );
-                if let Some(infer::RelateParamBound(_, t, _)) = origin {
-                    let t = self.resolve_vars_if_possible(t);
-                    match t.kind() {
-                        // We've got:
-                        // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-                        // suggest:
-                        // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-                        ty::Closure(..) | ty::Alias(ty::Opaque, ..) => {
-                            new_binding_suggestion(&mut err, type_param_span);
-                        }
-                        _ => {
-                            binding_suggestion(
-                                &mut err,
-                                type_param_span,
-                                bound_kind,
-                                new_lt,
-                                add_lt_suggs,
-                            );
-                        }
+        let new_lt = {
+            let generics = self.tcx.generics_of(lifetime_scope);
+            let mut used_names =
+                iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
+                    .flat_map(|g| &g.params)
+                    .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
+                    .map(|p| p.name)
+                    .collect::<Vec<_>>();
+            if let Some(hir_id) = self.tcx.opt_local_def_id_to_hir_id(lifetime_scope) {
+                // consider late-bound lifetimes ...
+                used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(|p| {
+                    match p {
+                        ty::BoundVariableKind::Region(lt) => lt.get_name(),
+                        _ => None,
                     }
-                }
-                err
+                }))
             }
+            (b'a'..=b'z')
+                .map(|c| format!("'{}", c as char))
+                .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
+                .unwrap_or("'lt".to_string())
         };
 
-        if let Some(origin) = origin {
-            self.note_region_origin(&mut err, &origin);
-        }
-        err
+        let mut visitor = LifetimeReplaceVisitor {
+            tcx: self.tcx,
+            needle: hir::LifetimeName::Param(lifetime_def_id),
+            add_lt_suggs,
+            new_lt: &new_lt,
+        };
+        match self.tcx.hir().expect_owner(lifetime_scope) {
+            hir::OwnerNode::Item(i) => visitor.visit_item(i),
+            hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
+            hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
+            hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
+            hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
+        }
+
+        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
+        let sugg = ast_generics
+            .span_for_lifetime_suggestion()
+            .map(|span| (span, format!("{new_lt}, ")))
+            .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
+        add_lt_suggs.push(sugg);
+
+        new_lt
     }
 
     fn report_sub_sup_conflict(
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index dd7f8d35441..c1e65ffe0a6 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -183,7 +183,7 @@ where
             // Avoid fetching the variance if we are in an invariant
             // context; no need, and it can induce dependency cycles
             // (e.g., #41849).
-            relate::relate_args(self, a_subst, b_subst)
+            relate::relate_args_invariantly(self, a_subst, b_subst)
         } else {
             let tcx = self.tcx();
             let opt_variances = tcx.variances_of(item_def_id);
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index e92ba05aa67..4a6d1bc682b 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -13,6 +13,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 2510ce71460..7799af37008 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -9,6 +9,7 @@ use rustc_session::config::DebugInfo;
 use rustc_session::config::Input;
 use rustc_session::config::InstrumentXRay;
 use rustc_session::config::LinkSelfContained;
+use rustc_session::config::Polonius;
 use rustc_session::config::TraitSolver;
 use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
 use rustc_session::config::{
@@ -814,7 +815,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(panic_abort_tests, true);
     tracked!(panic_in_drop, PanicStrategy::Abort);
     tracked!(plt, Some(true));
-    tracked!(polonius, true);
+    tracked!(polonius, Polonius::Legacy);
     tracked!(precise_enum_drop_elaboration, false);
     tracked!(print_fuel, Some("abc".to_string()));
     tracked!(profile, true);
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 536f78a73ed..be9465ba23d 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2258,23 +2258,19 @@ impl EarlyLintPass for IncompleteInternalFeatures {
             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
             .filter(|(&name, _)| features.incomplete(name) || features.internal(name))
             .for_each(|(&name, &span)| {
-                let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
-                    .map(|n| BuiltinFeatureIssueNote { n });
-
                 if features.incomplete(name) {
+                    let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
+                        .map(|n| BuiltinFeatureIssueNote { n });
                     let help =
                         HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
+
                     cx.emit_spanned_lint(
                         INCOMPLETE_FEATURES,
                         span,
                         BuiltinIncompleteFeatures { name, note, help },
                     );
                 } else {
-                    cx.emit_spanned_lint(
-                        INTERNAL_FEATURES,
-                        span,
-                        BuiltinInternalFeatures { name, note },
-                    );
+                    cx.emit_spanned_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name });
                 }
             });
     }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index af2132fb899..d7a666aa72b 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -27,6 +27,8 @@
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index c776d3bb7fe..594ef97b3ff 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -412,8 +412,6 @@ pub struct BuiltinIncompleteFeatures {
 #[note]
 pub struct BuiltinInternalFeatures {
     pub name: Symbol,
-    #[subdiagnostic]
-    pub note: Option<BuiltinFeatureIssueNote>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 44cf1591c7d..d252f651c78 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -140,13 +140,15 @@ declare_lint! {
 pub struct TypeLimits {
     /// Id of the last visited negated expression
     negated_expr_id: Option<hir::HirId>,
+    /// Span of the last visited negated expression
+    negated_expr_span: Option<Span>,
 }
 
 impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS, INVALID_NAN_COMPARISONS]);
 
 impl TypeLimits {
     pub fn new() -> TypeLimits {
-        TypeLimits { negated_expr_id: None }
+        TypeLimits { negated_expr_id: None, negated_expr_span: None }
     }
 }
 
@@ -426,17 +428,15 @@ fn lint_int_literal<'tcx>(
             return;
         }
 
-        let lit = cx
-            .sess()
-            .source_map()
-            .span_to_snippet(lit.span)
-            .expect("must get snippet from literal");
+        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 help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
 
         cx.emit_spanned_lint(
             OVERFLOWING_LITERALS,
-            e.span,
+            span,
             OverflowingInt { ty: t.name_str(), lit, min, max, help },
         );
     }
@@ -622,9 +622,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
         match e.kind {
             hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
-                // propagate negation, if the negation itself isn't negated
+                // Propagate negation, if the negation itself isn't negated
                 if self.negated_expr_id != Some(e.hir_id) {
                     self.negated_expr_id = Some(expr.hir_id);
+                    self.negated_expr_span = Some(e.span);
                 }
             }
             hir::ExprKind::Binary(binop, ref l, ref r) => {
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index b729c40228b..31565db1b79 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -795,6 +795,20 @@ LLVMRustOptimize(
   CGSCCAnalysisManager CGAM;
   ModuleAnalysisManager MAM;
 
+  if (LLVMPluginsLen) {
+    auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen);
+    SmallVector<StringRef> Plugins;
+    PluginsStr.split(Plugins, ',', -1, false);
+    for (auto PluginPath: Plugins) {
+      auto Plugin = PassPlugin::Load(PluginPath.str());
+      if (!Plugin) {
+        LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
+        return LLVMRustResult::Failure;
+      }
+      Plugin->registerPassBuilderCallbacks(PB);
+    }
+  }
+
   FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
 
   Triple TargetTriple(TheModule->getTargetTriple());
@@ -918,20 +932,6 @@ LLVMRustOptimize(
     }
   }
 
-  if (LLVMPluginsLen) {
-    auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen);
-    SmallVector<StringRef> Plugins;
-    PluginsStr.split(Plugins, ',', -1, false);
-    for (auto PluginPath: Plugins) {
-      auto Plugin = PassPlugin::Load(PluginPath.str());
-      if (!Plugin) {
-        LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
-        return LLVMRustResult::Failure;
-      }
-      Plugin->registerPassBuilderCallbacks(PB);
-    }
-  }
-
   ModulePassManager MPM;
   bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
   if (!NoPrepopulatePasses) {
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index eb70961503d..518c20c9fa8 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -1,6 +1,9 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 // NOTE: This crate only exists to allow linking on mingw targets.
 
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 3e43bcb3b8f..0c9ec556549 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -74,6 +74,11 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
         Some(v) => &v != "0",
     };
 
+    let verbose_thread_ids = match env::var_os(String::from(env) + "_THREAD_IDS") {
+        None => false,
+        Some(v) => &v == "1",
+    };
+
     let layer = tracing_tree::HierarchicalLayer::default()
         .with_writer(io::stderr)
         .with_indent_lines(true)
@@ -81,9 +86,9 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
         .with_targets(true)
         .with_verbose_exit(verbose_entry_exit)
         .with_verbose_entry(verbose_entry_exit)
-        .with_indent_amount(2);
-    #[cfg(all(parallel_compiler, debug_assertions))]
-    let layer = layer.with_thread_ids(true).with_thread_names(true);
+        .with_indent_amount(2)
+        .with_thread_ids(verbose_thread_ids)
+        .with_thread_names(verbose_thread_ids);
 
     let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
     match env::var(format!("{env}_BACKTRACE")) {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 69221475356..14bbe65d5f1 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard};
 use rustc_expand::base::SyntaxExtension;
+use rustc_fs_util::try_canonicalize;
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::IndexVec;
@@ -31,7 +32,7 @@ use std::error::Error;
 use std::ops::Fn;
 use std::path::Path;
 use std::time::Duration;
-use std::{cmp, env, iter};
+use std::{cmp, iter};
 
 pub struct CStore {
     metadata_loader: Box<MetadataLoaderDyn>,
@@ -677,7 +678,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         stable_crate_id: StableCrateId,
     ) -> Result<&'static [ProcMacro], CrateError> {
         // Make sure the path contains a / or the linker will search for it.
-        let path = env::current_dir().unwrap().join(path);
+        let path = try_canonicalize(path).unwrap();
         let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
 
         let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index fa77b36c4c5..ddeb39669dc 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(decl_macro)]
 #![feature(extract_if)]
 #![feature(generators)]
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 4af2d83e9c7..77643715fff 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -970,12 +970,15 @@ impl<'hir> Map<'hir> {
                 // SyntaxContext of the visibility.
                 sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span)
             }
+            // Impls, including their where clauses.
+            Node::Item(Item {
+                kind: ItemKind::Impl(Impl { generics, .. }),
+                span: outer_span,
+                ..
+            }) => until_within(*outer_span, generics.where_clause_span),
             // Constants and Statics.
             Node::Item(Item {
-                kind:
-                    ItemKind::Const(ty, ..)
-                    | ItemKind::Static(ty, ..)
-                    | ItemKind::Impl(Impl { self_ty: ty, .. }),
+                kind: ItemKind::Const(ty, ..) | ItemKind::Static(ty, ..),
                 span: outer_span,
                 ..
             })
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index fe4fc3761b3..dee18dc1162 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -23,6 +23,8 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 908ab8b613e..c66f64dde32 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -448,14 +448,14 @@ impl<'tcx> TyCtxt<'tcx> {
                     debug!("stability: skipping span={:?} since it is internal", span);
                     return EvalResult::Allow;
                 }
-                if self.features().active(feature) {
+                if self.features().declared(feature) {
                     return EvalResult::Allow;
                 }
 
                 // If this item was previously part of a now-stabilized feature which is still
                 // active (i.e. the user hasn't removed the attribute for the stabilized feature
                 // yet) then allow use of this item.
-                if let Some(implied_by) = implied_by && self.features().active(implied_by) {
+                if let Some(implied_by) = implied_by && self.features().declared(implied_by) {
                     return EvalResult::Allow;
                 }
 
@@ -532,7 +532,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     debug!("body stability: skipping span={:?} since it is internal", span);
                     return EvalResult::Allow;
                 }
-                if self.features().active(feature) {
+                if self.features().declared(feature) {
                     return EvalResult::Allow;
                 }
 
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 8f63ed757ba..4e429f316e8 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -213,10 +213,10 @@ impl<'tcx> Const<'tcx> {
     pub fn try_to_scalar(self) -> Option<Scalar> {
         match self {
             Const::Ty(c) => match c.kind() {
-                ty::ConstKind::Value(valtree) => match valtree {
-                    ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
-                    ty::ValTree::Branch(_) => None,
-                },
+                ty::ConstKind::Value(valtree) if c.ty().is_primitive() => {
+                    // A valtree of a type where leaves directly represent the scalar const value.
+                    Some(valtree.unwrap_leaf().into())
+                }
                 _ => None,
             },
             Const::Val(val, _) => val.try_to_scalar(),
@@ -279,7 +279,16 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Option<Scalar> {
-        self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+        match self {
+            Const::Ty(c) if c.ty().is_primitive() => {
+                // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
+                // are valtree leaves, and *not* on references. (References should return the
+                // pointer here, which valtrees don't represent.)
+                let val = c.eval(tcx, param_env, None).ok()?;
+                Some(val.unwrap_leaf().into())
+            }
+            _ => self.eval(tcx, param_env, None).ok()?.try_to_scalar(),
+        }
     }
 
     #[inline]
@@ -288,16 +297,7 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Option<ScalarInt> {
-        match self {
-            // If the constant is already evaluated, we shortcut here.
-            Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
-                valtree.try_to_scalar_int()
-            },
-            // This is a more general form of the previous case.
-            _ => {
-                self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
-            },
-        }
+        self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 34b6250a89d..f979f736b15 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1562,6 +1562,23 @@ impl Location {
     }
 }
 
+/// `DefLocation` represents the location of a definition - either an argument or an assignment
+/// within MIR body.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum DefLocation {
+    Argument,
+    Body(Location),
+}
+
+impl DefLocation {
+    pub fn dominates(self, location: Location, dominators: &Dominators<BasicBlock>) -> bool {
+        match self {
+            DefLocation::Argument => true,
+            DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
+        }
+    }
+}
+
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index b1f83796862..11376345052 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -12,7 +12,6 @@ use rustc_hir::hir_id::{HirId, OwnerId};
 use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::FieldIdx;
 
 /// Placeholder for `CrateNum`'s "local" counterpart
 #[derive(Copy, Clone, Debug)]
@@ -360,30 +359,6 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) {
     }
 }
 
-impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) {
-    type CacheSelector = DefaultCacheSelector<Self>;
-
-    fn default_span(&self, _: TyCtxt<'_>) -> Span {
-        DUMMY_SP
-    }
-}
-
-impl<'tcx> Key for (mir::ConstValue<'tcx>, Ty<'tcx>) {
-    type CacheSelector = DefaultCacheSelector<Self>;
-
-    fn default_span(&self, _: TyCtxt<'_>) -> Span {
-        DUMMY_SP
-    }
-}
-
-impl<'tcx> Key for mir::ConstAlloc<'tcx> {
-    type CacheSelector = DefaultCacheSelector<Self>;
-
-    fn default_span(&self, _: TyCtxt<'_>) -> Span {
-        DUMMY_SP
-    }
-}
-
 impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
@@ -416,14 +391,6 @@ impl<'tcx> Key for GenericArg<'tcx> {
     }
 }
 
-impl<'tcx> Key for mir::Const<'tcx> {
-    type CacheSelector = DefaultCacheSelector<Self>;
-
-    fn default_span(&self, _: TyCtxt<'_>) -> Span {
-        DUMMY_SP
-    }
-}
-
 impl<'tcx> Key for ty::Const<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 89934e4350e..08f7434a4a9 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -581,13 +581,13 @@ pub enum BindingMode {
     ByRef(BorrowKind),
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct FieldPat<'tcx> {
     pub field: FieldIdx,
     pub pattern: Box<Pat<'tcx>>,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct Pat<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
@@ -664,7 +664,7 @@ impl<'tcx> IntoDiagnosticArg for Pat<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct Ascription<'tcx> {
     pub annotation: CanonicalUserTypeAnnotation<'tcx>,
     /// Variance to use when relating the `user_ty` to the **type of the value being
@@ -688,7 +688,7 @@ pub struct Ascription<'tcx> {
     pub variance: ty::Variance,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub enum PatKind<'tcx> {
     /// A wildcard pattern: `_`.
     Wild,
@@ -702,7 +702,9 @@ pub enum PatKind<'tcx> {
     Binding {
         mutability: Mutability,
         name: Symbol,
+        #[type_visitable(ignore)]
         mode: BindingMode,
+        #[type_visitable(ignore)]
         var: LocalVarId,
         ty: Ty<'tcx>,
         subpattern: Option<Box<Pat<'tcx>>>,
@@ -771,10 +773,11 @@ pub enum PatKind<'tcx> {
     },
 }
 
-#[derive(Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)]
 pub struct PatRange<'tcx> {
     pub lo: mir::Const<'tcx>,
     pub hi: mir::Const<'tcx>,
+    #[type_visitable(ignore)]
     pub end: RangeEnd,
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 83adbc3c790..1ccb81dcb9b 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1057,16 +1057,21 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region.
-    pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
-        let (suitable_region_binding_scope, bound_region) = match *region {
-            ty::ReFree(ref free_region) => {
-                (free_region.scope.expect_local(), free_region.bound_region)
+    pub fn is_suitable_region(self, mut region: Region<'tcx>) -> Option<FreeRegionInfo> {
+        let (suitable_region_binding_scope, bound_region) = loop {
+            let def_id = match region.kind() {
+                ty::ReFree(fr) => fr.bound_region.get_id()?.as_local()?,
+                ty::ReEarlyBound(ebr) => ebr.def_id.expect_local(),
+                _ => return None, // not a free region
+            };
+            let scope = self.local_parent(def_id);
+            if self.def_kind(scope) == DefKind::OpaqueTy {
+                // Lifetime params of opaque types are synthetic and thus irrelevant to
+                // diagnostics. Map them back to their origin!
+                region = self.map_rpit_lifetime_to_fn_lifetime(def_id);
+                continue;
             }
-            ty::ReEarlyBound(ref ebr) => (
-                self.local_parent(ebr.def_id.expect_local()),
-                ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
-            ),
-            _ => return None, // not a free region
+            break (scope, ty::BrNamed(def_id.into(), self.item_name(def_id.into())));
         };
 
         let is_impl_item = match self.hir().find_by_def_id(suitable_region_binding_scope) {
@@ -1074,7 +1079,7 @@ impl<'tcx> TyCtxt<'tcx> {
             Some(Node::ImplItem(..)) => {
                 self.is_bound_region_in_impl_item(suitable_region_binding_scope)
             }
-            _ => return None,
+            _ => false,
         };
 
         Some(FreeRegionInfo {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index e9d763afa68..96268006353 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -8,6 +8,7 @@ use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
 use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_target::spec::abi;
 use std::iter;
@@ -134,7 +135,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
 }
 
 #[inline]
-pub fn relate_args<'tcx, R: TypeRelation<'tcx>>(
+pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
     a_arg: GenericArgsRef<'tcx>,
     b_arg: GenericArgsRef<'tcx>,
@@ -273,7 +274,20 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> {
         if a.def_id != b.def_id {
             Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let args = relation.relate(a.args, b.args)?;
+            let args = match relation.tcx().def_kind(a.def_id) {
+                DefKind::OpaqueTy => relate_args_with_variances(
+                    relation,
+                    a.def_id,
+                    relation.tcx().variances_of(a.def_id),
+                    a.args,
+                    b.args,
+                    false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
+                )?,
+                DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => {
+                    relate_args_invariantly(relation, a.args, b.args)?
+                }
+                def => bug!("unknown alias DefKind: {def:?}"),
+            };
             Ok(relation.tcx().mk_alias_ty(a.def_id, args))
         }
     }
@@ -315,7 +329,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let args = relate_args(relation, a.args, b.args)?;
+            let args = relate_args_invariantly(relation, a.args, b.args)?;
             Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args))
         }
     }
@@ -331,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let args = relate_args(relation, a.args, b.args)?;
+            let args = relate_args_invariantly(relation, a.args, b.args)?;
             Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
         }
     }
@@ -449,7 +463,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             // All Generator types with the same id represent
             // the (anonymous) type of the same generator expression. So
             // all of their regions should be equated.
-            let args = relation.relate(a_args, b_args)?;
+            let args = relate_args_invariantly(relation, a_args, b_args)?;
             Ok(Ty::new_generator(tcx, a_id, args, movability))
         }
 
@@ -459,7 +473,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             // All GeneratorWitness types with the same id represent
             // the (anonymous) type of the same generator expression. So
             // all of their regions should be equated.
-            let args = relation.relate(a_args, b_args)?;
+            let args = relate_args_invariantly(relation, a_args, b_args)?;
             Ok(Ty::new_generator_witness(tcx, a_id, args))
         }
 
@@ -467,7 +481,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             // All Closure types with the same id represent
             // the (anonymous) type of the same closure expression. So
             // all of their regions should be equated.
-            let args = relation.relate(a_args, b_args)?;
+            let args = relate_args_invariantly(relation, a_args, b_args)?;
             Ok(Ty::new_closure(tcx, a_id, &args))
         }
 
@@ -536,24 +550,6 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(Ty::new_fn_ptr(tcx, fty))
         }
 
-        // The args of opaque types may not all be invariant, so we have
-        // to treat them separately from other aliases.
-        (
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, args: a_args, .. }),
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, args: b_args, .. }),
-        ) if a_def_id == b_def_id => {
-            let opt_variances = tcx.variances_of(a_def_id);
-            let args = relate_args_with_variances(
-                relation,
-                a_def_id,
-                opt_variances,
-                a_args,
-                b_args,
-                false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
-            )?;
-            Ok(Ty::new_opaque(tcx, a_def_id, args))
-        }
-
         // Alias tend to mostly already be handled downstream due to normalization.
         (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => {
             let alias_ty = relation.relate(a_data, b_data)?;
@@ -709,7 +705,7 @@ impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> {
         a: ty::ClosureArgs<'tcx>,
         b: ty::ClosureArgs<'tcx>,
     ) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> {
-        let args = relate_args(relation, a.args, b.args)?;
+        let args = relate_args_invariantly(relation, a.args, b.args)?;
         Ok(ty::ClosureArgs { args })
     }
 }
@@ -720,7 +716,7 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorArgs<'tcx> {
         a: ty::GeneratorArgs<'tcx>,
         b: ty::GeneratorArgs<'tcx>,
     ) -> RelateResult<'tcx, ty::GeneratorArgs<'tcx>> {
-        let args = relate_args(relation, a.args, b.args)?;
+        let args = relate_args_invariantly(relation, a.args, b.args)?;
         Ok(ty::GeneratorArgs { args })
     }
 }
@@ -731,7 +727,7 @@ impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> {
         a: GenericArgsRef<'tcx>,
         b: GenericArgsRef<'tcx>,
     ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
-        relate_args(relation, a, b)
+        relate_args_invariantly(relation, a, b)
     }
 }
 
@@ -835,19 +831,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> {
     }
 }
 
-impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
-    fn relate<R: TypeRelation<'tcx>>(
-        relation: &mut R,
-        a: ty::ProjectionPredicate<'tcx>,
-        b: ty::ProjectionPredicate<'tcx>,
-    ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
-        Ok(ty::ProjectionPredicate {
-            projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
-            term: relation.relate(a.term, b.term)?,
-        })
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Error handling
 
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index ce021923f64..db3886b32be 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -173,7 +173,7 @@ mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
 
 mir_build_literal_in_range_out_of_bounds =
     literal out of range for `{$ty}`
-    .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
+    .label = this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
 
 mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
     lower range bound must be less than or equal to upper
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index bee5ac550dd..4f98932a88d 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -551,6 +551,7 @@ pub struct LiteralOutOfRange<'tcx> {
     #[label]
     pub span: Span,
     pub ty: Ty<'tcx>,
+    pub min: i128,
     pub max: u128,
 }
 
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 d440ca31926..93434dd3cc2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -19,7 +19,7 @@ use rustc_hir::HirId;
 use rustc_middle::thir::visit::{self, Visitor};
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
@@ -682,6 +682,12 @@ fn non_exhaustive_match<'p, 'tcx>(
     arms: &[ArmId],
     expr_span: Span,
 ) -> ErrorGuaranteed {
+    for &arm in arms {
+        if let Err(err) = thir[arm].pattern.error_reported() {
+            return err;
+        }
+    }
+
     let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
         ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
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 ae442466029..fde6defd87f 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,7 +7,7 @@ use rustc_middle::mir;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
 use rustc_session::lint;
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause};
@@ -48,7 +48,7 @@ struct ConstToPat<'tcx> {
     // This tracks if we emitted some hard error for a given const value, so that
     // we will not subsequently issue an irrelevant lint for the same const
     // value.
-    saw_const_match_error: Cell<bool>,
+    saw_const_match_error: Cell<Option<ErrorGuaranteed>>,
 
     // This tracks if we emitted some diagnostic for a given const value, so that
     // we will not subsequently issue an irrelevant lint for the same const
@@ -84,7 +84,7 @@ impl<'tcx> ConstToPat<'tcx> {
             span,
             infcx,
             param_env: pat_ctxt.param_env,
-            saw_const_match_error: Cell::new(false),
+            saw_const_match_error: Cell::new(None),
             saw_const_match_lint: Cell::new(false),
             behind_reference: Cell::new(false),
             treat_byte_string_as_slice: pat_ctxt
@@ -154,7 +154,7 @@ impl<'tcx> ConstToPat<'tcx> {
             }),
         };
 
-        if !self.saw_const_match_error.get() {
+        if self.saw_const_match_error.get().is_none() {
             // If we were able to successfully convert the const to some pat (possibly with some
             // lints, but no errors), double-check that all types in the const implement
             // `Structural` and `PartialEq`.
@@ -180,23 +180,26 @@ impl<'tcx> ConstToPat<'tcx> {
 
             if let Some(non_sm_ty) = structural {
                 if !self.type_has_partial_eq_impl(cv.ty()) {
-                    if let ty::Adt(def, ..) = non_sm_ty.kind() {
+                    let e = if let ty::Adt(def, ..) = non_sm_ty.kind() {
                         if def.is_union() {
                             let err = UnionPattern { span: self.span };
-                            self.tcx().sess.emit_err(err);
+                            self.tcx().sess.emit_err(err)
                         } else {
                             // fatal avoids ICE from resolution of nonexistent method (rare case).
                             self.tcx()
                                 .sess
-                                .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty });
+                                .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty })
                         }
                     } else {
                         let err = InvalidPattern { span: self.span, non_sm_ty };
-                        self.tcx().sess.emit_err(err);
-                    }
+                        self.tcx().sess.emit_err(err)
+                    };
                     // All branches above emitted an error. Don't print any more lints.
-                    // The pattern we return is irrelevant since we errored.
-                    return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
+                    // We errored. Signal that in the pattern, so that follow up errors can be silenced.
+                    let kind = PatKind::Constant {
+                        value: mir::Const::Ty(ty::Const::new_error(self.tcx(), e, cv.ty())),
+                    };
+                    return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
                 } else if !self.saw_const_match_lint.get() {
                     if let Some(mir_structural_match_violation) = mir_structural_match_violation {
                         match non_sm_ty.kind() {
@@ -330,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> {
             // Backwards compatibility hack because we can't cause hard errors on these
             // types, so we compare them via `PartialEq::eq` at runtime.
             ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => {
-                if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() {
+                if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() {
                     self.saw_const_match_lint.set(true);
                     tcx.emit_spanned_lint(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
@@ -345,18 +348,18 @@ impl<'tcx> ConstToPat<'tcx> {
                 return Err(FallbackToOpaqueConst);
             }
             ty::FnDef(..) => {
-                self.saw_const_match_error.set(true);
-                tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
-                // We errored, so the pattern we generate is irrelevant.
-                PatKind::Wild
+                let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
+                self.saw_const_match_error.set(Some(e));
+                // We errored. Signal that in the pattern, so that follow up errors can be silenced.
+                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
             }
             ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
-                self.saw_const_match_error.set(true);
                 let err = TypeNotStructural { span, non_sm_ty: ty };
-                tcx.sess.emit_err(err);
-                // We errored, so the pattern we generate is irrelevant.
-                PatKind::Wild
+                let e = tcx.sess.emit_err(err);
+                self.saw_const_match_error.set(Some(e));
+                // We errored. Signal that in the pattern, so that follow up errors can be silenced.
+                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
             }
             ty::Adt(adt_def, args) if adt_def.is_enum() => {
                 let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
@@ -416,7 +419,9 @@ impl<'tcx> ConstToPat<'tcx> {
                 // instead of a hard error.
                 ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
                     if self.behind_reference.get() {
-                        if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() {
+                        if self.saw_const_match_error.get().is_none()
+                            && !self.saw_const_match_lint.get()
+                        {
                             self.saw_const_match_lint.set(true);
                             tcx.emit_spanned_lint(
                                 lint::builtin::INDIRECT_STRUCTURAL_MATCH,
@@ -427,14 +432,20 @@ impl<'tcx> ConstToPat<'tcx> {
                         }
                         return Err(FallbackToOpaqueConst);
                     } else {
-                        if !self.saw_const_match_error.get() {
-                            self.saw_const_match_error.set(true);
+                        if let Some(e) = self.saw_const_match_error.get() {
+                            // We already errored. Signal that in the pattern, so that follow up errors can be silenced.
+                            PatKind::Constant {
+                                value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
+                            }
+                        } else {
                             let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
-                            tcx.sess.emit_err(err);
+                            let e = tcx.sess.emit_err(err);
+                            self.saw_const_match_error.set(Some(e));
+                            // We errored. Signal that in the pattern, so that follow up errors can be silenced.
+                            PatKind::Constant {
+                                value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
+                            }
                         }
-                        tcx.sess.delay_span_bug(span, "`saw_const_match_error` set but no error?");
-                        // We errored, so the pattern we generate is irrelevant.
-                        PatKind::Wild
                     }
                 }
                 // All other references are converted into deref patterns and then recursively
@@ -443,11 +454,11 @@ impl<'tcx> ConstToPat<'tcx> {
                 _ => {
                     if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
                         let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
-                        tcx.sess.emit_err(err);
-
-                        // FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns.
-                        // We errored, so the pattern we generate is irrelevant.
-                        PatKind::Wild
+                        let e = tcx.sess.emit_err(err);
+                        // We errored. Signal that in the pattern, so that follow up errors can be silenced.
+                        PatKind::Constant {
+                            value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
+                        }
                     } else {
                         let old = self.behind_reference.replace(true);
                         // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
@@ -474,15 +485,15 @@ impl<'tcx> ConstToPat<'tcx> {
             }
             ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
             _ => {
-                self.saw_const_match_error.set(true);
                 let err = InvalidPattern { span, non_sm_ty: ty };
-                tcx.sess.emit_err(err);
-                // We errored, so the pattern we generate is irrelevant.
-                PatKind::Wild
+                let e = tcx.sess.emit_err(err);
+                self.saw_const_match_error.set(Some(e));
+                // We errored. Signal that in the pattern, so that follow up errors can be silenced.
+                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
             }
         };
 
-        if !self.saw_const_match_error.get()
+        if self.saw_const_match_error.get().is_none()
             && !self.saw_const_match_lint.get()
             && mir_structural_match_violation
             // FIXME(#73448): Find a way to bring const qualification into parity with
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index fe47a1cd78c..25726c5a872 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -20,15 +20,15 @@ use rustc_index::Idx;
 use rustc_middle::mir::interpret::{
     ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
 };
-use rustc_middle::mir::{self, Const, UserTypeProjection};
-use rustc_middle::mir::{BorrowKind, Mutability};
+use rustc_middle::mir::{self, BorrowKind, Const, Mutability, UserTypeProjection};
 use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
-use rustc_middle::ty::CanonicalUserTypeAnnotation;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, AdtDef, Region, Ty, TyCtxt, UserType};
-use rustc_middle::ty::{GenericArg, GenericArgsRef};
-use rustc_span::{Span, Symbol};
-use rustc_target::abi::FieldIdx;
+use rustc_middle::ty::layout::IntegerExt;
+use rustc_middle::ty::{
+    self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt,
+    TypeVisitableExt, UserType,
+};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
+use rustc_target::abi::{FieldIdx, Integer};
 
 use std::cmp::Ordering;
 
@@ -85,127 +85,159 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         )
     }
 
-    fn lower_range_expr(
+    fn lower_pattern_range_endpoint(
         &mut self,
-        expr: &'tcx hir::Expr<'tcx>,
-    ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
-        match self.lower_lit(expr) {
-            PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
-                (kind, Some(ascription))
+        expr: Option<&'tcx hir::Expr<'tcx>>,
+    ) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> {
+        match expr {
+            None => Ok((None, None)),
+            Some(expr) => {
+                let (kind, ascr) = match self.lower_lit(expr) {
+                    PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
+                        (kind, Some(ascription))
+                    }
+                    kind => (kind, None),
+                };
+                let value = if let PatKind::Constant { value } = kind {
+                    value
+                } else {
+                    let msg = format!(
+                        "found bad range pattern endpoint `{expr:?}` outside of error recovery"
+                    );
+                    return Err(self.tcx.sess.delay_span_bug(expr.span, msg));
+                };
+                Ok((Some(value), ascr))
             }
-            kind => (kind, None),
         }
     }
 
+    /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we
+    /// encounter a range pattern like `-130i8..2`: if we believe `eval_bits`, this looks like a
+    /// range where the endpoints are in the wrong order. To avoid a confusing error message, we
+    /// check for overflow then.
+    /// This is only called when the range is already known to be malformed.
+    fn error_on_literal_overflow(
+        &self,
+        expr: Option<&'tcx hir::Expr<'tcx>>,
+        ty: Ty<'tcx>,
+    ) -> Result<(), ErrorGuaranteed> {
+        use hir::{ExprKind, UnOp};
+        use rustc_ast::ast::LitKind;
+
+        let Some(mut expr) = expr else {
+            return Ok(());
+        };
+        let span = expr.span;
+
+        // We need to inspect the original expression, because if we only inspect the output of
+        // `eval_bits`, an overflowed value has already been wrapped around.
+        // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
+        let mut negated = false;
+        if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind {
+            negated = true;
+            expr = sub_expr;
+        }
+        let ExprKind::Lit(lit) = expr.kind else {
+            return Ok(());
+        };
+        let LitKind::Int(lit_val, _) = lit.node else {
+            return Ok(());
+        };
+        let (min, max): (i128, u128) = match ty.kind() {
+            ty::Int(ity) => {
+                let size = Integer::from_int_ty(&self.tcx, *ity).size();
+                (size.signed_int_min(), size.signed_int_max() as u128)
+            }
+            ty::Uint(uty) => {
+                let size = Integer::from_uint_ty(&self.tcx, *uty).size();
+                (0, size.unsigned_int_max())
+            }
+            _ => {
+                return Ok(());
+            }
+        };
+        // Detect literal value out of range `[min, max]` inclusive, avoiding use of `-min` to
+        // prevent overflow/panic.
+        if (negated && lit_val > max + 1) || (!negated && lit_val > max) {
+            return Err(self.tcx.sess.emit_err(LiteralOutOfRange { span, ty, min, max }));
+        }
+        Ok(())
+    }
+
     fn lower_pattern_range(
         &mut self,
-        ty: Ty<'tcx>,
-        lo: mir::Const<'tcx>,
-        hi: mir::Const<'tcx>,
+        lo_expr: Option<&'tcx hir::Expr<'tcx>>,
+        hi_expr: Option<&'tcx hir::Expr<'tcx>>,
         end: RangeEnd,
+        ty: Ty<'tcx>,
         span: Span,
-        lo_expr: Option<&hir::Expr<'tcx>>,
-        hi_expr: Option<&hir::Expr<'tcx>>,
-    ) -> PatKind<'tcx> {
+    ) -> Result<PatKind<'tcx>, ErrorGuaranteed> {
+        if lo_expr.is_none() && hi_expr.is_none() {
+            let msg = format!("found twice-open range pattern (`..`) outside of error recovery");
+            return Err(self.tcx.sess.delay_span_bug(span, msg));
+        }
+
+        let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?;
+        let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?;
+
+        let lo = lo.unwrap_or_else(|| {
+            // Unwrap is ok because the type is known to be numeric.
+            let lo = ty.numeric_min_val(self.tcx).unwrap();
+            mir::Const::from_ty_const(lo, self.tcx)
+        });
+        let hi = hi.unwrap_or_else(|| {
+            // Unwrap is ok because the type is known to be numeric.
+            let hi = ty.numeric_max_val(self.tcx).unwrap();
+            mir::Const::from_ty_const(hi, self.tcx)
+        });
         assert_eq!(lo.ty(), ty);
         assert_eq!(hi.ty(), ty);
+
         let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env);
-        let max = || {
-            self.tcx
-                .layout_of(self.param_env.with_reveal_all_normalized(self.tcx).and(ty))
-                .ok()
-                .unwrap()
-                .size
-                .unsigned_int_max()
-        };
-        match (end, cmp) {
+        let mut kind = match (end, cmp) {
             // `x..y` where `x < y`.
             // Non-empty because the range includes at least `x`.
             (RangeEnd::Excluded, Some(Ordering::Less)) => {
                 PatKind::Range(Box::new(PatRange { lo, hi, end }))
             }
-            // `x..y` where `x >= y`. The range is empty => error.
-            (RangeEnd::Excluded, _) => {
-                let mut lower_overflow = false;
-                let mut higher_overflow = false;
-                if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
-                    && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
-                {
-                    if lo.eval_bits(self.tcx, self.param_env) != val {
-                        lower_overflow = true;
-                        self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
-                    }
-                }
-                if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
-                    && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
-                {
-                    if hi.eval_bits(self.tcx, self.param_env) != val {
-                        higher_overflow = true;
-                        self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
-                    }
-                }
-                if !lower_overflow && !higher_overflow {
-                    self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
-                }
-                PatKind::Wild
-            }
             // `x..=y` where `x == y`.
             (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
             // `x..=y` where `x < y`.
             (RangeEnd::Included, Some(Ordering::Less)) => {
                 PatKind::Range(Box::new(PatRange { lo, hi, end }))
             }
-            // `x..=y` where `x > y` hence the range is empty => error.
-            (RangeEnd::Included, _) => {
-                let mut lower_overflow = false;
-                let mut higher_overflow = false;
-                if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
-                    && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
-                {
-                    if lo.eval_bits(self.tcx, self.param_env) != val {
-                        lower_overflow = true;
-                        self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
+            // `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error.
+            _ => {
+                // Emit a more appropriate message if there was overflow.
+                self.error_on_literal_overflow(lo_expr, ty)?;
+                self.error_on_literal_overflow(hi_expr, ty)?;
+                let e = match end {
+                    RangeEnd::Included => {
+                        self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
+                            span,
+                            teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()),
+                        })
                     }
-                }
-                if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
-                    && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
-                {
-                    if hi.eval_bits(self.tcx, self.param_env) != val {
-                        higher_overflow = true;
-                        self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
+                    RangeEnd::Excluded => {
+                        self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span })
                     }
-                }
-                if !lower_overflow && !higher_overflow {
-                    self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
-                        span,
-                        teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()),
-                    });
-                }
-                PatKind::Wild
+                };
+                return Err(e);
             }
-        }
-    }
+        };
 
-    fn normalize_range_pattern_ends(
-        &self,
-        ty: Ty<'tcx>,
-        lo: Option<&PatKind<'tcx>>,
-        hi: Option<&PatKind<'tcx>>,
-    ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> {
-        match (lo, hi) {
-            (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
-                Some((*lo, *hi))
-            }
-            (Some(PatKind::Constant { value: lo }), None) => {
-                let hi = ty.numeric_max_val(self.tcx)?;
-                Some((*lo, mir::Const::from_ty_const(hi, self.tcx)))
-            }
-            (None, Some(PatKind::Constant { value: hi })) => {
-                let lo = ty.numeric_min_val(self.tcx)?;
-                Some((mir::Const::from_ty_const(lo, self.tcx), *hi))
+        // If we are handling a range with associated constants (e.g.
+        // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
+        // constants somewhere. Have them on the range pattern.
+        for ascr in [lo_ascr, hi_ascr] {
+            if let Some(ascription) = ascr {
+                kind = PatKind::AscribeUserType {
+                    ascription,
+                    subpattern: Box::new(Pat { span, ty, kind }),
+                };
             }
-            _ => None,
         }
+        Ok(kind)
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -220,37 +252,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
             hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
                 let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
-                let lo_span = lo_expr.map_or(pat.span, |e| e.span);
-                let lo = lo_expr.map(|e| self.lower_range_expr(e));
-                let hi = hi_expr.map(|e| self.lower_range_expr(e));
-
-                let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x));
-                let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) {
-                    Some((lc, hc)) => {
-                        self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr)
-                    }
-                    None => {
-                        let msg = format!(
-                            "found bad range pattern `{:?}` outside of error recovery",
-                            (&lo, &hi),
-                        );
-                        self.tcx.sess.delay_span_bug(pat.span, msg);
-                        PatKind::Wild
-                    }
-                };
-
-                // If we are handling a range with associated constants (e.g.
-                // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
-                // constants somewhere. Have them on the range pattern.
-                for end in &[lo, hi] {
-                    if let Some((_, Some(ascription))) = end {
-                        let subpattern = Box::new(Pat { span: pat.span, ty, kind });
-                        kind =
-                            PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
-                    }
-                }
-
-                kind
+                // FIXME?: returning `_` can cause inaccurate "unreachable" warnings. This can be
+                // fixed by returning `PatKind::Const(ConstKind::Error(...))` if #115937 gets
+                // merged.
+                self.lower_pattern_range(lo_expr, hi_expr, end, ty, span).unwrap_or(PatKind::Wild)
             }
 
             hir::PatKind::Path(ref qpath) => {
diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs
new file mode 100644
index 00000000000..fd5e8cf2955
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs
@@ -0,0 +1,20 @@
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+
+/// Return the set of locals that appear in debuginfo.
+pub fn debuginfo_locals(body: &Body<'_>) -> BitSet<Local> {
+    let mut visitor = DebuginfoLocals(BitSet::new_empty(body.local_decls.len()));
+    for debuginfo in body.var_debug_info.iter() {
+        visitor.visit_var_debug_info(debuginfo);
+    }
+    visitor.0
+}
+
+struct DebuginfoLocals(BitSet<Local>);
+
+impl Visitor<'_> for DebuginfoLocals {
+    fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) {
+        self.0.insert(local);
+    }
+}
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 0cdbee19d2c..ecf46715cd0 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -35,6 +35,7 @@ pub use self::framework::{
 
 use self::move_paths::MoveData;
 
+pub mod debuginfo;
 pub mod drop_flag_effects;
 pub mod elaborate_drops;
 mod errors;
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 64e262c6c93..b51bfe8c6ab 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -22,7 +22,6 @@ use rustc_middle::ty::{
 };
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
-use rustc_trait_selection::traits;
 
 use crate::const_prop::CanConstProp;
 use crate::const_prop::ConstPropMachine;
@@ -35,9 +34,9 @@ use crate::MirLint;
 /// Severely regress performance.
 const MAX_ALLOC_LIMIT: u64 = 1024;
 
-pub struct ConstProp;
+pub struct ConstPropLint;
 
-impl<'tcx> MirLint<'tcx> for ConstProp {
+impl<'tcx> MirLint<'tcx> for ConstPropLint {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         if body.tainted_by_errors.is_some() {
             return;
@@ -49,61 +48,25 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
         }
 
         let def_id = body.source.def_id().expect_local();
-        let is_fn_like = tcx.def_kind(def_id).is_fn_like();
-        let is_assoc_const = tcx.def_kind(def_id) == DefKind::AssocConst;
+        let def_kind = tcx.def_kind(def_id);
+        let is_fn_like = def_kind.is_fn_like();
+        let is_assoc_const = def_kind == DefKind::AssocConst;
 
         // Only run const prop on functions, methods, closures and associated constants
         if !is_fn_like && !is_assoc_const {
             // skip anon_const/statics/consts because they'll be evaluated by miri anyway
-            trace!("ConstProp skipped for {:?}", def_id);
+            trace!("ConstPropLint skipped for {:?}", def_id);
             return;
         }
 
-        let is_generator = tcx.type_of(def_id.to_def_id()).instantiate_identity().is_generator();
         // FIXME(welseywiser) const prop doesn't work on generators because of query cycles
         // computing their layout.
-        if is_generator {
-            trace!("ConstProp skipped for generator {:?}", def_id);
+        if let DefKind::Generator = def_kind {
+            trace!("ConstPropLint skipped for generator {:?}", def_id);
             return;
         }
 
-        // Check if it's even possible to satisfy the 'where' clauses
-        // for this item.
-        // This branch will never be taken for any normal function.
-        // However, it's possible to `#!feature(trivial_bounds)]` to write
-        // a function with impossible to satisfy clauses, e.g.:
-        // `fn foo() where String: Copy {}`
-        //
-        // We don't usually need to worry about this kind of case,
-        // since we would get a compilation error if the user tried
-        // to call it. However, since we can do const propagation
-        // even without any calls to the function, we need to make
-        // sure that it even makes sense to try to evaluate the body.
-        // If there are unsatisfiable where clauses, then all bets are
-        // off, and we just give up.
-        //
-        // We manually filter the predicates, skipping anything that's not
-        // "global". We are in a potentially generic context
-        // (e.g. we are evaluating a function without substituting generic
-        // parameters, so this filtering serves two purposes:
-        //
-        // 1. We skip evaluating any predicates that we would
-        // never be able prove are unsatisfiable (e.g. `<T as Foo>`
-        // 2. We avoid trying to normalize predicates involving generic
-        // parameters (e.g. `<T as Foo>::MyItem`). This can confuse
-        // the normalization code (leading to cycle errors), since
-        // it's usually never invoked in this way.
-        let predicates = tcx
-            .predicates_of(def_id.to_def_id())
-            .predicates
-            .iter()
-            .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
-        if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
-            trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
-            return;
-        }
-
-        trace!("ConstProp starting for {:?}", def_id);
+        trace!("ConstPropLint starting for {:?}", def_id);
 
         // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
         // constants, instead of just checking for const-folding succeeding.
@@ -112,7 +75,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
         let mut linter = ConstPropagator::new(body, tcx);
         linter.visit_body(body);
 
-        trace!("ConstProp done for {:?}", def_id);
+        trace!("ConstPropLint done for {:?}", def_id);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 812633348e3..39027d21f06 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,8 +1,9 @@
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::graph::dominators::{self, Dominators};
 use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
-use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind};
+use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
 
 use std::cmp::Ordering;
 use std::ops::{Index, IndexMut};
@@ -36,9 +37,8 @@ impl CoverageGraph {
                 }
                 let bcb_data = &bcbs[bcb];
                 let mut bcb_successors = Vec::new();
-                for successor in
-                    bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
-                        .filter_map(|successor_bb| bb_to_bcb[successor_bb])
+                for successor in bcb_filtered_successors(&mir_body, bcb_data.last_bb())
+                    .filter_map(|successor_bb| bb_to_bcb[successor_bb])
                 {
                     if !seen[successor] {
                         seen[successor] = true;
@@ -80,10 +80,9 @@ impl CoverageGraph {
         // intentionally omits unwind paths.
         // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
         // `catch_unwind()` handlers.
-        let mir_cfg_without_unwind = ShortCircuitPreorder::new(&mir_body, bcb_filtered_successors);
 
         let mut basic_blocks = Vec::new();
-        for (bb, data) in mir_cfg_without_unwind {
+        for bb in short_circuit_preorder(mir_body, bcb_filtered_successors) {
             if let Some(last) = basic_blocks.last() {
                 let predecessors = &mir_body.basic_blocks.predecessors()[bb];
                 if predecessors.len() > 1 || !predecessors.contains(last) {
@@ -109,7 +108,7 @@ impl CoverageGraph {
             }
             basic_blocks.push(bb);
 
-            let term = data.terminator();
+            let term = mir_body[bb].terminator();
 
             match term.kind {
                 TerminatorKind::Return { .. }
@@ -316,11 +315,6 @@ impl BasicCoverageBlockData {
     pub fn last_bb(&self) -> BasicBlock {
         *self.basic_blocks.last().unwrap()
     }
-
-    #[inline(always)]
-    pub fn terminator<'a, 'tcx>(&self, mir_body: &'a mir::Body<'tcx>) -> &'a Terminator<'tcx> {
-        &mir_body[self.last_bb()].terminator()
-    }
 }
 
 /// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`)
@@ -362,26 +356,28 @@ impl std::fmt::Debug for BcbBranch {
     }
 }
 
-// Returns the `Terminator`s non-unwind successors.
+// Returns the subset of a block's successors that are relevant to the coverage
+// graph, i.e. those that do not represent unwinds or unreachable branches.
 // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
 // `catch_unwind()` handlers.
 fn bcb_filtered_successors<'a, 'tcx>(
     body: &'a mir::Body<'tcx>,
-    term_kind: &'a TerminatorKind<'tcx>,
-) -> Box<dyn Iterator<Item = BasicBlock> + 'a> {
-    Box::new(
-        match &term_kind {
-            // SwitchInt successors are never unwind, and all of them should be traversed.
-            TerminatorKind::SwitchInt { ref targets, .. } => {
-                None.into_iter().chain(targets.all_targets().into_iter().copied())
-            }
-            // For all other kinds, return only the first successor, if any, and ignore unwinds.
-            // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
-            // `next().into_iter()`) into the `mir::Successors` aliased type.
-            _ => term_kind.successors().next().into_iter().chain((&[]).into_iter().copied()),
-        }
-        .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable),
-    )
+    bb: BasicBlock,
+) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx> {
+    let terminator = body[bb].terminator();
+
+    let take_n_successors = match terminator.kind {
+        // SwitchInt successors are never unwinds, so all of them should be traversed.
+        TerminatorKind::SwitchInt { .. } => usize::MAX,
+        // For all other kinds, return only the first successor (if any), ignoring any
+        // unwind successors.
+        _ => 1,
+    };
+
+    terminator
+        .successors()
+        .take(take_n_successors)
+        .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable)
 }
 
 /// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
@@ -553,66 +549,28 @@ pub(super) fn find_loop_backedges(
     backedges
 }
 
-pub struct ShortCircuitPreorder<
-    'a,
-    'tcx,
-    F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
-> {
+fn short_circuit_preorder<'a, 'tcx, F, Iter>(
     body: &'a mir::Body<'tcx>,
-    visited: BitSet<BasicBlock>,
-    worklist: Vec<BasicBlock>,
     filtered_successors: F,
-}
-
-impl<
-    'a,
-    'tcx,
-    F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
-> ShortCircuitPreorder<'a, 'tcx, F>
+) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx>
+where
+    F: Fn(&'a mir::Body<'tcx>, BasicBlock) -> Iter,
+    Iter: Iterator<Item = BasicBlock>,
 {
-    pub fn new(
-        body: &'a mir::Body<'tcx>,
-        filtered_successors: F,
-    ) -> ShortCircuitPreorder<'a, 'tcx, F> {
-        let worklist = vec![mir::START_BLOCK];
-
-        ShortCircuitPreorder {
-            body,
-            visited: BitSet::new_empty(body.basic_blocks.len()),
-            worklist,
-            filtered_successors,
-        }
-    }
-}
-
-impl<
-    'a,
-    'tcx,
-    F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
-> Iterator for ShortCircuitPreorder<'a, 'tcx, F>
-{
-    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
+    let mut visited = BitSet::new_empty(body.basic_blocks.len());
+    let mut worklist = vec![mir::START_BLOCK];
 
-    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
-        while let Some(idx) = self.worklist.pop() {
-            if !self.visited.insert(idx) {
+    std::iter::from_fn(move || {
+        while let Some(bb) = worklist.pop() {
+            if !visited.insert(bb) {
                 continue;
             }
 
-            let data = &self.body[idx];
-
-            if let Some(ref term) = data.terminator {
-                self.worklist.extend((self.filtered_successors)(&self.body, &term.kind));
-            }
+            worklist.extend(filtered_successors(body, bb));
 
-            return Some((idx, data));
+            return Some(bb);
         }
 
         None
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let size = self.body.basic_blocks.len() - self.visited.count();
-        (size, Some(size))
-    }
+    })
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index dd87694f97c..e08019bea21 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,15 +1,13 @@
-use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
+use std::cell::OnceCell;
 
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_index::IndexVec;
-use rustc_middle::mir::{
-    self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
-};
-use rustc_span::source_map::original_sp;
+use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind};
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
 
-use std::cell::OnceCell;
+use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
+
+mod from_mir;
 
 pub(super) struct CoverageSpans {
     /// Map from BCBs to their list of coverage spans.
@@ -53,27 +51,13 @@ impl CoverageSpans {
     }
 }
 
-#[derive(Debug, Copy, Clone)]
-pub(super) enum CoverageStatement {
-    Statement(BasicBlock, Span, usize),
-    Terminator(BasicBlock, Span),
-}
-
-impl CoverageStatement {
-    pub fn span(&self) -> Span {
-        match self {
-            Self::Statement(_, span, _) | Self::Terminator(_, span) => *span,
-        }
-    }
-}
-
 /// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
 /// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
 /// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
 /// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the
-/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s.
+/// `merged_spans` vectors, and the `Span`s to cover the extent of the combined `Span`s.
 ///
-/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that
+/// Note: A span merged into another CoverageSpan may come from a `BasicBlock` that
 /// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches
 /// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
 /// `dominates()` the `BasicBlock`s in this `CoverageSpan`.
@@ -83,7 +67,9 @@ struct CoverageSpan {
     pub expn_span: Span,
     pub current_macro_or_none: OnceCell<Option<Symbol>>,
     pub bcb: BasicCoverageBlock,
-    pub coverage_statements: Vec<CoverageStatement>,
+    /// List of all the original spans from MIR that have been merged into this
+    /// span. Mainly used to precisely skip over gaps when truncating a span.
+    pub merged_spans: Vec<Span>,
     pub is_closure: bool,
 }
 
@@ -94,7 +80,7 @@ impl CoverageSpan {
             expn_span: fn_sig_span,
             current_macro_or_none: Default::default(),
             bcb: START_BCB,
-            coverage_statements: vec![],
+            merged_spans: vec![],
             is_closure: false,
         }
     }
@@ -104,8 +90,6 @@ impl CoverageSpan {
         span: Span,
         expn_span: Span,
         bcb: BasicCoverageBlock,
-        bb: BasicBlock,
-        stmt_index: usize,
     ) -> Self {
         let is_closure = match statement.kind {
             StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
@@ -119,23 +103,18 @@ impl CoverageSpan {
             expn_span,
             current_macro_or_none: Default::default(),
             bcb,
-            coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
+            merged_spans: vec![span],
             is_closure,
         }
     }
 
-    pub fn for_terminator(
-        span: Span,
-        expn_span: Span,
-        bcb: BasicCoverageBlock,
-        bb: BasicBlock,
-    ) -> Self {
+    pub fn for_terminator(span: Span, expn_span: Span, bcb: BasicCoverageBlock) -> Self {
         Self {
             span,
             expn_span,
             current_macro_or_none: Default::default(),
             bcb,
-            coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
+            merged_spans: vec![span],
             is_closure: false,
         }
     }
@@ -143,15 +122,13 @@ impl CoverageSpan {
     pub fn merge_from(&mut self, mut other: CoverageSpan) {
         debug_assert!(self.is_mergeable(&other));
         self.span = self.span.to(other.span);
-        self.coverage_statements.append(&mut other.coverage_statements);
+        self.merged_spans.append(&mut other.merged_spans);
     }
 
     pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) {
-        self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos);
-        if let Some(highest_covstmt) =
-            self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi())
-        {
-            self.span = self.span.with_hi(highest_covstmt.span().hi());
+        self.merged_spans.retain(|span| span.hi() <= cutoff_pos);
+        if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() {
+            self.span = self.span.with_hi(max_hi);
         }
     }
 
@@ -205,13 +182,7 @@ impl CoverageSpan {
 ///  * Merge spans that represent continuous (both in source code and control flow), non-branching
 ///    execution
 ///  * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
-struct CoverageSpansGenerator<'a, 'tcx> {
-    /// The MIR, used to look up `BasicBlockData`.
-    mir_body: &'a mir::Body<'tcx>,
-
-    /// A `Span` covering the signature of function for the MIR.
-    fn_sig_span: Span,
-
+struct CoverageSpansGenerator<'a> {
     /// A `Span` covering the function body of the MIR (typically from left curly brace to right
     /// curly brace).
     body_span: Span,
@@ -221,7 +192,7 @@ struct CoverageSpansGenerator<'a, 'tcx> {
 
     /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative
     /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
-    sorted_spans_iter: Option<std::vec::IntoIter<CoverageSpan>>,
+    sorted_spans_iter: std::vec::IntoIter<CoverageSpan>,
 
     /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the
     /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to
@@ -261,7 +232,7 @@ struct CoverageSpansGenerator<'a, 'tcx> {
     refined_spans: Vec<CoverageSpan>,
 }
 
-impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
+impl<'a> CoverageSpansGenerator<'a> {
     /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
     /// counted.
     ///
@@ -284,17 +255,22 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
     /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
     /// to be).
     pub(super) fn generate_coverage_spans(
-        mir_body: &'a mir::Body<'tcx>,
+        mir_body: &mir::Body<'_>,
         fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
         body_span: Span,
         basic_coverage_blocks: &'a CoverageGraph,
     ) -> Vec<CoverageSpan> {
-        let mut coverage_spans = Self {
+        let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
             mir_body,
             fn_sig_span,
             body_span,
             basic_coverage_blocks,
-            sorted_spans_iter: None,
+        );
+
+        let coverage_spans = Self {
+            body_span,
+            basic_coverage_blocks,
+            sorted_spans_iter: sorted_spans.into_iter(),
             refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
             some_curr: None,
             curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
@@ -304,48 +280,9 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
             pending_dups: Vec::new(),
         };
 
-        let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
-
-        coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
-
         coverage_spans.to_refined_spans()
     }
 
-    fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
-        let mut initial_spans =
-            Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks.len() * 2);
-        for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
-            initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data));
-        }
-
-        if initial_spans.is_empty() {
-            // This can happen if, for example, the function is unreachable (contains only a
-            // `BasicBlock`(s) with an `Unreachable` terminator).
-            return initial_spans;
-        }
-
-        initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span));
-
-        initial_spans.sort_by(|a, b| {
-            // First sort by span start.
-            Ord::cmp(&a.span.lo(), &b.span.lo())
-                // If span starts are the same, sort by span end in reverse order.
-                // This ensures that if spans A and B are adjacent in the list,
-                // and they overlap but are not equal, then either:
-                // - Span A extends further left, or
-                // - Both have the same start and span A extends further right
-                .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse())
-                // If both spans are equal, sort the BCBs in dominator order,
-                // so that dominating BCBs come before other BCBs they dominate.
-                .then_with(|| self.basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb))
-                // If two spans are otherwise identical, put closure spans first,
-                // as this seems to be what the refinement step expects.
-                .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
-        });
-
-        initial_spans
-    }
-
     /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
     /// de-duplicated `CoverageSpan`s.
     fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
@@ -485,48 +422,6 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
         }
     }
 
-    // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
-    // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
-    // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
-    // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
-    // `Statement`s and/or `Terminator`s.)
-    fn bcb_to_initial_coverage_spans(
-        &self,
-        bcb: BasicCoverageBlock,
-        bcb_data: &'a BasicCoverageBlockData,
-    ) -> Vec<CoverageSpan> {
-        bcb_data
-            .basic_blocks
-            .iter()
-            .flat_map(|&bb| {
-                let data = &self.mir_body[bb];
-                data.statements
-                    .iter()
-                    .enumerate()
-                    .filter_map(move |(index, statement)| {
-                        filtered_statement_span(statement).map(|span| {
-                            CoverageSpan::for_statement(
-                                statement,
-                                function_source_span(span, self.body_span),
-                                span,
-                                bcb,
-                                bb,
-                                index,
-                            )
-                        })
-                    })
-                    .chain(filtered_terminator_span(data.terminator()).map(|span| {
-                        CoverageSpan::for_terminator(
-                            function_source_span(span, self.body_span),
-                            span,
-                            bcb,
-                            bb,
-                        )
-                    }))
-            })
-            .collect()
-    }
-
     fn curr(&self) -> &CoverageSpan {
         self.some_curr
             .as_ref()
@@ -589,7 +484,7 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
             self.some_prev = Some(curr);
             self.prev_original_span = self.curr_original_span;
         }
-        while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
+        while let Some(curr) = self.sorted_spans_iter.next() {
             debug!("FOR curr={:?}", curr);
             if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
                 debug!(
@@ -757,7 +652,7 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
         if self.pending_dups.is_empty() {
             let curr_span = self.curr().span;
             self.prev_mut().cutoff_statements_at(curr_span.lo());
-            if self.prev().coverage_statements.is_empty() {
+            if self.prev().merged_spans.is_empty() {
                 debug!("  ... no non-overlapping statements to add");
             } else {
                 debug!("  ... adding modified prev={:?}", self.prev());
@@ -774,104 +669,3 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
         self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb)
     }
 }
-
-/// If the MIR `Statement` has a span contributive to computing coverage spans,
-/// return it; otherwise return `None`.
-fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
-    match statement.kind {
-        // These statements have spans that are often outside the scope of the executed source code
-        // for their parent `BasicBlock`.
-        StatementKind::StorageLive(_)
-        | StatementKind::StorageDead(_)
-        // Coverage should not be encountered, but don't inject coverage coverage
-        | StatementKind::Coverage(_)
-        // Ignore `ConstEvalCounter`s
-        | StatementKind::ConstEvalCounter
-        // Ignore `Nop`s
-        | StatementKind::Nop => None,
-
-        // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
-        // statements be more consistent?
-        //
-        // FakeReadCause::ForGuardBinding, in this example:
-        //     match somenum {
-        //         x if x < 1 => { ... }
-        //     }...
-        // The BasicBlock within the match arm code included one of these statements, but the span
-        // for it covered the `1` in this source. The actual statements have nothing to do with that
-        // source span:
-        //     FakeRead(ForGuardBinding, _4);
-        // where `_4` is:
-        //     _4 = &_1; (at the span for the first `x`)
-        // and `_1` is the `Place` for `somenum`.
-        //
-        // If and when the Issue is resolved, remove this special case match pattern:
-        StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None,
-
-        // Retain spans from all other statements
-        StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
-        | StatementKind::Intrinsic(..)
-        | StatementKind::Assign(_)
-        | StatementKind::SetDiscriminant { .. }
-        | StatementKind::Deinit(..)
-        | StatementKind::Retag(_, _)
-        | StatementKind::PlaceMention(..)
-        | StatementKind::AscribeUserType(_, _) => {
-            Some(statement.source_info.span)
-        }
-    }
-}
-
-/// If the MIR `Terminator` has a span contributive to computing coverage spans,
-/// return it; otherwise return `None`.
-fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
-    match terminator.kind {
-        // These terminators have spans that don't positively contribute to computing a reasonable
-        // span of actually executed source code. (For example, SwitchInt terminators extracted from
-        // an `if condition { block }` has a span that includes the executed block, if true,
-        // but for coverage, the code region executed, up to *and* through the SwitchInt,
-        // actually stops before the if's block.)
-        TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
-        | TerminatorKind::Assert { .. }
-        | TerminatorKind::Drop { .. }
-        | TerminatorKind::SwitchInt { .. }
-        // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
-        | TerminatorKind::FalseEdge { .. }
-        | TerminatorKind::Goto { .. } => None,
-
-        // Call `func` operand can have a more specific span when part of a chain of calls
-        | TerminatorKind::Call { ref func, .. } => {
-            let mut span = terminator.source_info.span;
-            if let mir::Operand::Constant(box constant) = func {
-                if constant.span.lo() > span.lo() {
-                    span = span.with_lo(constant.span.lo());
-                }
-            }
-            Some(span)
-        }
-
-        // Retain spans from all other terminators
-        TerminatorKind::UnwindResume
-        | TerminatorKind::UnwindTerminate(_)
-        | TerminatorKind::Return
-        | TerminatorKind::Yield { .. }
-        | TerminatorKind::GeneratorDrop
-        | TerminatorKind::FalseUnwind { .. }
-        | TerminatorKind::InlineAsm { .. } => {
-            Some(terminator.source_info.span)
-        }
-    }
-}
-
-/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
-/// within the function's body source. This span is guaranteed to be contained
-/// within, or equal to, the `body_span`. If the extrapolated span is not
-/// contained within the `body_span`, the `body_span` is returned.
-///
-/// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
-/// etc.).
-#[inline]
-fn function_source_span(span: Span, body_span: Span) -> Span {
-    let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
-    if body_span.contains(original_span) { original_span } else { body_span }
-}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
new file mode 100644
index 00000000000..4c20997e633
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -0,0 +1,184 @@
+use rustc_middle::mir::{
+    self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind,
+};
+use rustc_span::Span;
+
+use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
+use crate::coverage::spans::CoverageSpan;
+
+pub(super) fn mir_to_initial_sorted_coverage_spans(
+    mir_body: &mir::Body<'_>,
+    fn_sig_span: Span,
+    body_span: Span,
+    basic_coverage_blocks: &CoverageGraph,
+) -> Vec<CoverageSpan> {
+    let mut initial_spans = Vec::<CoverageSpan>::with_capacity(mir_body.basic_blocks.len() * 2);
+    for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
+        initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
+    }
+
+    if initial_spans.is_empty() {
+        // This can happen if, for example, the function is unreachable (contains only a
+        // `BasicBlock`(s) with an `Unreachable` terminator).
+        return initial_spans;
+    }
+
+    initial_spans.push(CoverageSpan::for_fn_sig(fn_sig_span));
+
+    initial_spans.sort_by(|a, b| {
+        // First sort by span start.
+        Ord::cmp(&a.span.lo(), &b.span.lo())
+            // If span starts are the same, sort by span end in reverse order.
+            // This ensures that if spans A and B are adjacent in the list,
+            // and they overlap but are not equal, then either:
+            // - Span A extends further left, or
+            // - Both have the same start and span A extends further right
+            .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse())
+            // If both spans are equal, sort the BCBs in dominator order,
+            // so that dominating BCBs come before other BCBs they dominate.
+            .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb))
+            // If two spans are otherwise identical, put closure spans first,
+            // as this seems to be what the refinement step expects.
+            .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
+    });
+
+    initial_spans
+}
+
+// Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
+// the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
+// for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
+// merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
+// `Statement`s and/or `Terminator`s.)
+fn bcb_to_initial_coverage_spans(
+    mir_body: &mir::Body<'_>,
+    body_span: Span,
+    bcb: BasicCoverageBlock,
+    bcb_data: &BasicCoverageBlockData,
+) -> Vec<CoverageSpan> {
+    bcb_data
+        .basic_blocks
+        .iter()
+        .flat_map(|&bb| {
+            let data = &mir_body[bb];
+            data.statements
+                .iter()
+                .filter_map(move |statement| {
+                    filtered_statement_span(statement).map(|span| {
+                        CoverageSpan::for_statement(
+                            statement,
+                            function_source_span(span, body_span),
+                            span,
+                            bcb,
+                        )
+                    })
+                })
+                .chain(filtered_terminator_span(data.terminator()).map(|span| {
+                    CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb)
+                }))
+        })
+        .collect()
+}
+
+/// If the MIR `Statement` has a span contributive to computing coverage spans,
+/// return it; otherwise return `None`.
+fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
+    match statement.kind {
+        // These statements have spans that are often outside the scope of the executed source code
+        // for their parent `BasicBlock`.
+        StatementKind::StorageLive(_)
+        | StatementKind::StorageDead(_)
+        // Coverage should not be encountered, but don't inject coverage coverage
+        | StatementKind::Coverage(_)
+        // Ignore `ConstEvalCounter`s
+        | StatementKind::ConstEvalCounter
+        // Ignore `Nop`s
+        | StatementKind::Nop => None,
+
+        // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
+        // statements be more consistent?
+        //
+        // FakeReadCause::ForGuardBinding, in this example:
+        //     match somenum {
+        //         x if x < 1 => { ... }
+        //     }...
+        // The BasicBlock within the match arm code included one of these statements, but the span
+        // for it covered the `1` in this source. The actual statements have nothing to do with that
+        // source span:
+        //     FakeRead(ForGuardBinding, _4);
+        // where `_4` is:
+        //     _4 = &_1; (at the span for the first `x`)
+        // and `_1` is the `Place` for `somenum`.
+        //
+        // If and when the Issue is resolved, remove this special case match pattern:
+        StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None,
+
+        // Retain spans from all other statements
+        StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
+        | StatementKind::Intrinsic(..)
+        | StatementKind::Assign(_)
+        | StatementKind::SetDiscriminant { .. }
+        | StatementKind::Deinit(..)
+        | StatementKind::Retag(_, _)
+        | StatementKind::PlaceMention(..)
+        | StatementKind::AscribeUserType(_, _) => {
+            Some(statement.source_info.span)
+        }
+    }
+}
+
+/// If the MIR `Terminator` has a span contributive to computing coverage spans,
+/// return it; otherwise return `None`.
+fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
+    match terminator.kind {
+        // These terminators have spans that don't positively contribute to computing a reasonable
+        // span of actually executed source code. (For example, SwitchInt terminators extracted from
+        // an `if condition { block }` has a span that includes the executed block, if true,
+        // but for coverage, the code region executed, up to *and* through the SwitchInt,
+        // actually stops before the if's block.)
+        TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
+        | TerminatorKind::Assert { .. }
+        | TerminatorKind::Drop { .. }
+        | TerminatorKind::SwitchInt { .. }
+        // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
+        | TerminatorKind::FalseEdge { .. }
+        | TerminatorKind::Goto { .. } => None,
+
+        // Call `func` operand can have a more specific span when part of a chain of calls
+        | TerminatorKind::Call { ref func, .. } => {
+            let mut span = terminator.source_info.span;
+            if let mir::Operand::Constant(box constant) = func {
+                if constant.span.lo() > span.lo() {
+                    span = span.with_lo(constant.span.lo());
+                }
+            }
+            Some(span)
+        }
+
+        // Retain spans from all other terminators
+        TerminatorKind::UnwindResume
+        | TerminatorKind::UnwindTerminate(_)
+        | TerminatorKind::Return
+        | TerminatorKind::Yield { .. }
+        | TerminatorKind::GeneratorDrop
+        | TerminatorKind::FalseUnwind { .. }
+        | TerminatorKind::InlineAsm { .. } => {
+            Some(terminator.source_info.span)
+        }
+    }
+}
+
+/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
+/// within the function's body source. This span is guaranteed to be contained
+/// within, or equal to, the `body_span`. If the extrapolated span is not
+/// contained within the `body_span`, the `body_span` is returned.
+///
+/// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
+/// etc.).
+#[inline]
+fn function_source_span(span: Span, body_span: Span) -> Span {
+    use rustc_span::source_map::original_sp;
+
+    let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
+    if body_span.contains(original_span) { original_span } else { body_span }
+}
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 7476d3ce927..ee7cb791c81 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -241,7 +241,7 @@ fn print_coverage_graphviz(
                         "    {:?} [label=\"{:?}: {}\"];\n{}",
                         bcb,
                         bcb,
-                        bcb_data.terminator(mir_body).kind.name(),
+                        mir_body[bcb_data.last_bb()].terminator().kind.name(),
                         basic_coverage_blocks
                             .successors(bcb)
                             .map(|successor| { format!("    {:?} -> {:?};", bcb, successor) })
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index ef14105041b..3d74ef7e327 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -13,10 +13,10 @@
 //!
 
 use crate::util::is_within_packed;
-use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::debuginfo::debuginfo_locals;
 use rustc_mir_dataflow::impls::{
     borrowed_locals, LivenessTransferFunction, MaybeTransitiveLiveLocals,
 };
@@ -26,8 +26,15 @@ use rustc_mir_dataflow::Analysis;
 ///
 /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
 /// can be generated via the [`borrowed_locals`] function.
-pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
-    let mut live = MaybeTransitiveLiveLocals::new(borrowed)
+pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let borrowed_locals = borrowed_locals(body);
+
+    // If the user requests complete debuginfo, mark the locals that appear in it as live, so
+    // we don't remove assignements to them.
+    let mut always_live = debuginfo_locals(body);
+    always_live.union(&borrowed_locals);
+
+    let mut live = MaybeTransitiveLiveLocals::new(&always_live)
         .into_engine(tcx, body)
         .iterate_to_fixpoint()
         .into_results_cursor(body);
@@ -48,7 +55,9 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
             for (index, arg) in args.iter().enumerate().rev() {
                 if let Operand::Copy(place) = *arg
                     && !place.is_indirect()
-                    && !borrowed.contains(place.local)
+                    // Do not skip the transformation if the local is in debuginfo, as we do
+                    // not really lose any information for this purpose.
+                    && !borrowed_locals.contains(place.local)
                     && !state.contains(place.local)
                     // If `place` is a projection of a disaligned field in a packed ADT,
                     // the move may be codegened as a pointer to that field.
@@ -75,7 +84,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
                 StatementKind::Assign(box (place, _))
                 | StatementKind::SetDiscriminant { place: box place, .. }
                 | StatementKind::Deinit(box place) => {
-                    if !place.is_indirect() && !borrowed.contains(place.local) {
+                    if !place.is_indirect() && !always_live.contains(place.local) {
                         live.seek_before_primary_effect(loc);
                         if !live.get().contains(place.local) {
                             patch.push(loc);
@@ -126,7 +135,6 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let borrowed = borrowed_locals(body);
-        eliminate(tcx, body, &borrowed);
+        eliminate(tcx, body);
     }
 }
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 319fb4eaf3e..6eb6cb069fe 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -95,6 +95,7 @@ pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        // unsound: https://github.com/rust-lang/rust/issues/95162
         sess.mir_opt_level() >= 3 && sess.opts.unstable_opts.unsound_mir_opts
     }
 
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 56bdc5a171a..c7529b954fe 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -63,7 +63,7 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_target::abi::{VariantIdx, FIRST_VARIANT};
 
-use crate::ssa::SsaLocals;
+use crate::ssa::{AssignedValue, SsaLocals};
 use crate::MirPass;
 
 pub struct GVN;
@@ -87,21 +87,28 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let dominators = body.basic_blocks.dominators().clone();
 
     let mut state = VnState::new(tcx, param_env, &ssa, &dominators, &body.local_decls);
-    for arg in body.args_iter() {
-        if ssa.is_ssa(arg) {
-            let value = state.new_opaque().unwrap();
-            state.assign(arg, value);
-        }
-    }
-
-    ssa.for_each_assignment_mut(&mut body.basic_blocks, |local, rvalue, location| {
-        let value = state.simplify_rvalue(rvalue, location).or_else(|| state.new_opaque()).unwrap();
-        // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as
-        // reusable if we have an exact type match.
-        if state.local_decls[local].ty == rvalue.ty(state.local_decls, tcx) {
+    ssa.for_each_assignment_mut(
+        body.basic_blocks.as_mut_preserves_cfg(),
+        |local, value, location| {
+            let value = match value {
+                // We do not know anything of this assigned value.
+                AssignedValue::Arg | AssignedValue::Terminator(_) => None,
+                // Try to get some insight.
+                AssignedValue::Rvalue(rvalue) => {
+                    let value = state.simplify_rvalue(rvalue, location);
+                    // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as
+                    // reusable if we have an exact type match.
+                    if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) {
+                        return;
+                    }
+                    value
+                }
+            };
+            // `next_opaque` is `Some`, so `new_opaque` must return `Some`.
+            let value = value.or_else(|| state.new_opaque()).unwrap();
             state.assign(local, value);
-        }
-    });
+        },
+    );
 
     // Stop creating opaques during replacement as it is useless.
     state.next_opaque = None;
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 886ff760481..0a8b13d6677 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -30,6 +30,9 @@ pub struct EnumSizeOpt {
 
 impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
     fn is_enabled(&self, sess: &Session) -> bool {
+        // There are some differences in behavior on wasm and ARM that are not properly
+        // understood, so we conservatively treat this optimization as unsound:
+        // https://github.com/rust-lang/rust/pull/85158#issuecomment-1101836457
         sess.opts.unstable_opts.unsound_mir_opts || sess.mir_opt_level() >= 3
     }
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index c0a09b7a761..9ee2f6dcea0 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -496,7 +496,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &elaborate_box_derefs::ElaborateBoxDerefs,
         &generator::StateTransform,
         &add_retag::AddRetag,
-        &Lint(const_prop_lint::ConstProp),
+        &Lint(const_prop_lint::ConstPropLint),
     ];
     pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
 }
@@ -554,8 +554,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &const_prop::ConstProp,
             &gvn::GVN,
             &dataflow_const_prop::DataflowConstProp,
-            //
-            // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0.
             &const_debuginfo::ConstDebugInfo,
             &o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
             &early_otherwise_branch::EarlyOtherwiseBranch,
@@ -613,6 +611,15 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
         return 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.
+    if let TerminatorKind::Unreachable = body.basic_blocks[START_BLOCK].terminator().kind
+        && body.basic_blocks[START_BLOCK].statements.is_empty()
+    {
+        return body;
+    }
+
     run_optimization_passes(tcx, &mut body);
 
     body
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 0d2d764c422..22f9c6f4f85 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -2,9 +2,8 @@
 
 use crate::MirPass;
 use rustc_middle::mir::*;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::symbol::sym;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 
 pub struct LowerIntrinsics;
@@ -16,12 +15,10 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
             let terminator = block.terminator.as_mut().unwrap();
             if let TerminatorKind::Call { func, args, destination, target, .. } =
                 &mut terminator.kind
+                && let ty::FnDef(def_id, generic_args) = *func.ty(local_decls, tcx).kind()
+                && tcx.is_intrinsic(def_id)
             {
-                let func_ty = func.ty(local_decls, tcx);
-                let Some((intrinsic_name, generic_args)) = resolve_rust_intrinsic(tcx, func_ty)
-                else {
-                    continue;
-                };
+                let intrinsic_name = tcx.item_name(def_id);
                 match intrinsic_name {
                     sym::unreachable => {
                         terminator.kind = TerminatorKind::Unreachable;
@@ -309,15 +306,3 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
         }
     }
 }
-
-fn resolve_rust_intrinsic<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    func_ty: Ty<'tcx>,
-) -> Option<(Symbol, GenericArgsRef<'tcx>)> {
-    if let ty::FnDef(def_id, args) = *func_ty.kind() {
-        if tcx.is_intrinsic(def_id) {
-            return Some((tcx.item_name(def_id), args));
-        }
-    }
-    None
-}
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index b7cc0db9559..ac52f0ae112 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -34,67 +34,44 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     }
 }
 
-struct SliceLenPatchInformation<'tcx> {
-    add_statement: Statement<'tcx>,
-    new_terminator_kind: TerminatorKind<'tcx>,
-}
-
 fn lower_slice_len_call<'tcx>(
     tcx: TyCtxt<'tcx>,
     block: &mut BasicBlockData<'tcx>,
     local_decls: &IndexSlice<Local, LocalDecl<'tcx>>,
     slice_len_fn_item_def_id: DefId,
 ) {
-    let mut patch_found: Option<SliceLenPatchInformation<'_>> = None;
-
     let terminator = block.terminator();
-    match &terminator.kind {
-        TerminatorKind::Call {
-            func,
-            args,
-            destination,
-            target: Some(bb),
-            call_source: CallSource::Normal,
-            ..
-        } => {
-            // some heuristics for fast rejection
-            if args.len() != 1 {
-                return;
-            }
-            let Some(arg) = args[0].place() else { return };
-            let func_ty = func.ty(local_decls, tcx);
-            match func_ty.kind() {
-                ty::FnDef(fn_def_id, _) if fn_def_id == &slice_len_fn_item_def_id => {
-                    // perform modifications
-                    // from something like `_5 = core::slice::<impl [u8]>::len(move _6) -> bb1`
-                    // into:
-                    // ```
-                    // _5 = Len(*_6)
-                    // goto bb1
-                    // ```
+    if let TerminatorKind::Call {
+        func,
+        args,
+        destination,
+        target: Some(bb),
+        call_source: CallSource::Normal,
+        ..
+    } = &terminator.kind
+        // some heuristics for fast rejection
+        && let [arg] = &args[..]
+        && let Some(arg) = arg.place()
+        && let ty::FnDef(fn_def_id, _) = func.ty(local_decls, tcx).kind()
+        && *fn_def_id == slice_len_fn_item_def_id
+    {
+        // perform modifications from something like:
+        //     _5 = core::slice::<impl [u8]>::len(move _6) -> bb1
+        // into:
+        //     _5 = Len(*_6)
+        //     goto bb1
 
-                    // make new RValue for Len
-                    let deref_arg = tcx.mk_place_deref(arg);
-                    let r_value = Rvalue::Len(deref_arg);
-                    let len_statement_kind =
-                        StatementKind::Assign(Box::new((*destination, r_value)));
-                    let add_statement =
-                        Statement { kind: len_statement_kind, source_info: terminator.source_info };
+        // make new RValue for Len
+        let deref_arg = tcx.mk_place_deref(arg);
+        let r_value = Rvalue::Len(deref_arg);
+        let len_statement_kind =
+            StatementKind::Assign(Box::new((*destination, r_value)));
+        let add_statement =
+            Statement { kind: len_statement_kind, source_info: terminator.source_info };
 
-                    // modify terminator into simple Goto
-                    let new_terminator_kind = TerminatorKind::Goto { target: *bb };
-
-                    let patch = SliceLenPatchInformation { add_statement, new_terminator_kind };
-
-                    patch_found = Some(patch);
-                }
-                _ => {}
-            }
-        }
-        _ => {}
-    }
+        // modify terminator into simple Goto
+        let new_terminator_kind = TerminatorKind::Goto { target: *bb };
 
-    if let Some(SliceLenPatchInformation { add_statement, new_terminator_kind }) = patch_found {
         block.statements.push(add_statement);
         block.terminator_mut().kind = new_terminator_kind;
     }
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index e1298b0654f..ff309bd10ec 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -34,7 +34,7 @@ pub struct RenameReturnPlace;
 
 impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // #111005
+        // unsound: #111005
         sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
     }
 
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index af9514ed6bb..8dc7b60c4e5 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -5,7 +5,6 @@
 //! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are
 //! `Freeze`, as we do not track that the assignment dominates all uses of the borrow.
 
-use either::Either;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
@@ -15,7 +14,7 @@ use rustc_middle::mir::*;
 
 pub struct SsaLocals {
     /// Assignments to each local. This defines whether the local is SSA.
-    assignments: IndexVec<Local, Set1<LocationExtended>>,
+    assignments: IndexVec<Local, Set1<DefLocation>>,
     /// We visit the body in reverse postorder, to ensure each local is assigned before it is used.
     /// We remember the order in which we saw the assignments to compute the SSA values in a single
     /// pass.
@@ -27,39 +26,10 @@ pub struct SsaLocals {
     direct_uses: IndexVec<Local, u32>,
 }
 
-/// We often encounter MIR bodies with 1 or 2 basic blocks. In those cases, it's unnecessary to
-/// actually compute dominators, we can just compare block indices because bb0 is always the first
-/// block, and in any body all other blocks are always dominated by bb0.
-struct SmallDominators<'a> {
-    inner: Option<&'a Dominators<BasicBlock>>,
-}
-
-impl SmallDominators<'_> {
-    fn dominates(&self, first: Location, second: Location) -> bool {
-        if first.block == second.block {
-            first.statement_index <= second.statement_index
-        } else if let Some(inner) = &self.inner {
-            inner.dominates(first.block, second.block)
-        } else {
-            first.block < second.block
-        }
-    }
-
-    fn check_dominates(&mut self, set: &mut Set1<LocationExtended>, loc: Location) {
-        let assign_dominates = match *set {
-            Set1::Empty | Set1::Many => false,
-            Set1::One(LocationExtended::Arg) => true,
-            Set1::One(LocationExtended::Plain(assign)) => {
-                self.dominates(assign.successor_within_block(), loc)
-            }
-        };
-        // We are visiting a use that is not dominated by an assignment.
-        // Either there is a cycle involved, or we are reading for uninitialized local.
-        // Bail out.
-        if !assign_dominates {
-            *set = Set1::Many;
-        }
-    }
+pub enum AssignedValue<'a, 'tcx> {
+    Arg,
+    Rvalue(&'a mut Rvalue<'tcx>),
+    Terminator(&'a mut TerminatorKind<'tcx>),
 }
 
 impl SsaLocals {
@@ -67,15 +37,14 @@ impl SsaLocals {
         let assignment_order = Vec::with_capacity(body.local_decls.len());
 
         let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
-        let dominators =
-            if body.basic_blocks.len() > 2 { Some(body.basic_blocks.dominators()) } else { None };
-        let dominators = SmallDominators { inner: dominators };
+        let dominators = body.basic_blocks.dominators();
 
         let direct_uses = IndexVec::from_elem(0, &body.local_decls);
         let mut visitor = SsaVisitor { assignments, assignment_order, dominators, direct_uses };
 
         for local in body.args_iter() {
-            visitor.assignments[local] = Set1::One(LocationExtended::Arg);
+            visitor.assignments[local] = Set1::One(DefLocation::Argument);
+            visitor.assignment_order.push(local);
         }
 
         // For SSA assignments, a RPO visit will see the assignment before it sees any use.
@@ -131,14 +100,7 @@ impl SsaLocals {
         location: Location,
     ) -> bool {
         match self.assignments[local] {
-            Set1::One(LocationExtended::Arg) => true,
-            Set1::One(LocationExtended::Plain(ass)) => {
-                if ass.block == location.block {
-                    ass.statement_index < location.statement_index
-                } else {
-                    dominators.dominates(ass.block, location.block)
-                }
-            }
+            Set1::One(def) => def.dominates(location, dominators),
             _ => false,
         }
     }
@@ -148,9 +110,9 @@ impl SsaLocals {
         body: &'a Body<'tcx>,
     ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>, Location)> + 'a {
         self.assignment_order.iter().filter_map(|&local| {
-            if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
+            if let Set1::One(DefLocation::Body(loc)) = self.assignments[local] {
+                let stmt = body.stmt_at(loc).left()?;
                 // `loc` must point to a direct assignment to `local`.
-                let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
                 let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() };
                 assert_eq!(target.as_local(), Some(local));
                 Some((local, rvalue, loc))
@@ -162,18 +124,33 @@ impl SsaLocals {
 
     pub fn for_each_assignment_mut<'tcx>(
         &self,
-        basic_blocks: &mut BasicBlocks<'tcx>,
-        mut f: impl FnMut(Local, &mut Rvalue<'tcx>, Location),
+        basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        mut f: impl FnMut(Local, AssignedValue<'_, 'tcx>, Location),
     ) {
         for &local in &self.assignment_order {
-            if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
-                // `loc` must point to a direct assignment to `local`.
-                let bbs = basic_blocks.as_mut_preserves_cfg();
-                let bb = &mut bbs[loc.block];
-                let stmt = &mut bb.statements[loc.statement_index];
-                let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else { bug!() };
-                assert_eq!(target.as_local(), Some(local));
-                f(local, rvalue, loc)
+            match self.assignments[local] {
+                Set1::One(DefLocation::Argument) => f(
+                    local,
+                    AssignedValue::Arg,
+                    Location { block: START_BLOCK, statement_index: 0 },
+                ),
+                Set1::One(DefLocation::Body(loc)) => {
+                    let bb = &mut basic_blocks[loc.block];
+                    let value = if loc.statement_index < bb.statements.len() {
+                        // `loc` must point to a direct assignment to `local`.
+                        let stmt = &mut bb.statements[loc.statement_index];
+                        let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else {
+                            bug!()
+                        };
+                        assert_eq!(target.as_local(), Some(local));
+                        AssignedValue::Rvalue(rvalue)
+                    } else {
+                        let term = bb.terminator_mut();
+                        AssignedValue::Terminator(&mut term.kind)
+                    };
+                    f(local, value, loc)
+                }
+                _ => {}
             }
         }
     }
@@ -224,19 +201,29 @@ impl SsaLocals {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum LocationExtended {
-    Plain(Location),
-    Arg,
-}
-
 struct SsaVisitor<'a> {
-    dominators: SmallDominators<'a>,
-    assignments: IndexVec<Local, Set1<LocationExtended>>,
+    dominators: &'a Dominators<BasicBlock>,
+    assignments: IndexVec<Local, Set1<DefLocation>>,
     assignment_order: Vec<Local>,
     direct_uses: IndexVec<Local, u32>,
 }
 
+impl SsaVisitor<'_> {
+    fn check_dominates(&mut self, local: Local, loc: Location) {
+        let set = &mut self.assignments[local];
+        let assign_dominates = match *set {
+            Set1::Empty | Set1::Many => false,
+            Set1::One(def) => def.dominates(loc, self.dominators),
+        };
+        // We are visiting a use that is not dominated by an assignment.
+        // Either there is a cycle involved, or we are reading for uninitialized local.
+        // Bail out.
+        if !assign_dominates {
+            *set = Set1::Many;
+        }
+    }
+}
+
 impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
     fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
         match ctxt {
@@ -254,7 +241,7 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
                 self.assignments[local] = Set1::Many;
             }
             PlaceContext::NonMutatingUse(_) => {
-                self.dominators.check_dominates(&mut self.assignments[local], loc);
+                self.check_dominates(local, loc);
                 self.direct_uses[local] += 1;
             }
             PlaceContext::NonUse(_) => {}
@@ -262,34 +249,34 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
     }
 
     fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, loc: Location) {
-        if place.projection.first() == Some(&PlaceElem::Deref) {
-            // Do not do anything for storage statements and debuginfo.
+        let location = match ctxt {
+            PlaceContext::MutatingUse(
+                MutatingUseContext::Store | MutatingUseContext::Call | MutatingUseContext::Yield,
+            ) => Some(DefLocation::Body(loc)),
+            _ => None,
+        };
+        if let Some(location) = location
+            && let Some(local) = place.as_local()
+        {
+            self.assignments[local].insert(location);
+            if let Set1::One(_) = self.assignments[local] {
+                // Only record if SSA-like, to avoid growing the vector needlessly.
+                self.assignment_order.push(local);
+            }
+        } else if place.projection.first() == Some(&PlaceElem::Deref) {
+            // Do not do anything for debuginfo.
             if ctxt.is_use() {
                 // Only change the context if it is a real use, not a "use" in debuginfo.
                 let new_ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
 
                 self.visit_projection(place.as_ref(), new_ctxt, loc);
-                self.dominators.check_dominates(&mut self.assignments[place.local], loc);
+                self.check_dominates(place.local, loc);
             }
-            return;
         } else {
             self.visit_projection(place.as_ref(), ctxt, loc);
             self.visit_local(place.local, ctxt, loc);
         }
     }
-
-    fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, loc: Location) {
-        if let Some(local) = place.as_local() {
-            self.assignments[local].insert(LocationExtended::Plain(loc));
-            if let Set1::One(_) = self.assignments[local] {
-                // Only record if SSA-like, to avoid growing the vector needlessly.
-                self.assignment_order.push(local);
-            }
-        } else {
-            self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), loc);
-        }
-        self.visit_rvalue(rvalue, loc);
-    }
 }
 
 #[instrument(level = "trace", skip(ssa, body))]
@@ -356,7 +343,7 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
 #[derive(Debug)]
 pub(crate) struct StorageLiveLocals {
     /// Set of "StorageLive" statements for each local.
-    storage_live: IndexVec<Local, Set1<LocationExtended>>,
+    storage_live: IndexVec<Local, Set1<DefLocation>>,
 }
 
 impl StorageLiveLocals {
@@ -366,13 +353,13 @@ impl StorageLiveLocals {
     ) -> StorageLiveLocals {
         let mut storage_live = IndexVec::from_elem(Set1::Empty, &body.local_decls);
         for local in always_storage_live_locals.iter() {
-            storage_live[local] = Set1::One(LocationExtended::Arg);
+            storage_live[local] = Set1::One(DefLocation::Argument);
         }
         for (block, bbdata) in body.basic_blocks.iter_enumerated() {
             for (statement_index, statement) in bbdata.statements.iter().enumerate() {
                 if let StatementKind::StorageLive(local) = statement.kind {
                     storage_live[local]
-                        .insert(LocationExtended::Plain(Location { block, statement_index }));
+                        .insert(DefLocation::Body(Location { block, statement_index }));
                 }
             }
         }
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 092bcb5c979..cb028a92d49 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -30,22 +30,17 @@ fn get_switched_on_type<'tcx>(
     let terminator = block_data.terminator();
 
     // Only bother checking blocks which terminate by switching on a local.
-    if let Some(local) = get_discriminant_local(&terminator.kind) {
-        let stmt_before_term = (!block_data.statements.is_empty())
-            .then(|| &block_data.statements[block_data.statements.len() - 1].kind);
-
-        if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term
-        {
-            if l.as_local() == Some(local) {
-                let ty = place.ty(body, tcx).ty;
-                if ty.is_enum() {
-                    return Some(ty);
-                }
-            }
-        }
+    if let Some(local) = get_discriminant_local(&terminator.kind)
+        && let [.., stmt_before_term] = &block_data.statements[..]
+        && let StatementKind::Assign(box (l, Rvalue::Discriminant(place))) = stmt_before_term.kind
+        && l.as_local() == Some(local)
+        && let ty = place.ty(body, tcx).ty
+        && ty.is_enum()
+    {
+        Some(ty)
+    } else {
+        None
     }
-
-    None
 }
 
 fn variant_discriminants<'tcx>(
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 8525a4e74c2..6ea177bb6ea 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -432,7 +432,7 @@ fn collect_items_rec<'tcx>(
                         hir::InlineAsmOperand::SymFn { anon_const } => {
                             let fn_ty =
                                 tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
-                            visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items, &[]);
+                            visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items);
                         }
                         hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
                             let instance = Instance::mono(tcx, *def_id);
@@ -593,11 +593,9 @@ struct MirUsedCollector<'a, 'tcx> {
     instance: Instance<'tcx>,
     /// Spans for move size lints already emitted. Helps avoid duplicate lints.
     move_size_spans: Vec<Span>,
-    /// If true, we should temporarily skip move size checks, because we are
-    /// processing an operand to a `skip_move_check_fns` function call.
-    skip_move_size_check: bool,
+    visiting_call_terminator: bool,
     /// Set of functions for which it is OK to move large data into.
-    skip_move_check_fns: Vec<DefId>,
+    skip_move_check_fns: Option<Vec<DefId>>,
 }
 
 impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -613,7 +611,20 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         )
     }
 
-    fn check_move_size(&mut self, limit: usize, operand: &mir::Operand<'tcx>, location: Location) {
+    fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
+        let limit = self.tcx.move_size_limit().0;
+        if limit == 0 {
+            return;
+        }
+
+        // This function is called by visit_operand() which visits _all_
+        // operands, including TerminatorKind::Call operands. But if
+        // check_fn_args_move_size() has been called, the operands have already
+        // been visited. Do not visit them again.
+        if self.visiting_call_terminator {
+            return;
+        }
+
         let limit = Size::from_bytes(limit);
         let ty = operand.ty(self.body, self.tcx);
         let ty = self.monomorphize(ty);
@@ -651,6 +662,38 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         );
         self.move_size_spans.push(source_info.span);
     }
+
+    fn check_fn_args_move_size(
+        &mut self,
+        callee_ty: Ty<'tcx>,
+        args: &[mir::Operand<'tcx>],
+        location: Location,
+    ) {
+        let limit = self.tcx.move_size_limit();
+        if limit.0 == 0 {
+            return;
+        }
+
+        if args.is_empty() {
+            return;
+        }
+
+        // Allow large moves into container types that themselves are cheap to move
+        let ty::FnDef(def_id, _) = *callee_ty.kind() else {
+            return;
+        };
+        if self
+            .skip_move_check_fns
+            .get_or_insert_with(|| build_skip_move_check_fns(self.tcx))
+            .contains(&def_id)
+        {
+            return;
+        }
+
+        for arg in args {
+            self.check_operand_move_size(arg, location);
+        }
+    }
 }
 
 impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
@@ -696,14 +739,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
             ) => {
                 let fn_ty = operand.ty(self.body, self.tcx);
                 let fn_ty = self.monomorphize(fn_ty);
-                visit_fn_use(
-                    self.tcx,
-                    fn_ty,
-                    false,
-                    span,
-                    &mut self.output,
-                    &self.skip_move_check_fns,
-                );
+                visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output);
             }
             mir::Rvalue::Cast(
                 mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
@@ -775,17 +811,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         };
 
         match terminator.kind {
-            mir::TerminatorKind::Call { ref func, .. } => {
+            mir::TerminatorKind::Call { ref func, ref args, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
                 let callee_ty = self.monomorphize(callee_ty);
-                self.skip_move_size_check = visit_fn_use(
-                    self.tcx,
-                    callee_ty,
-                    true,
-                    source,
-                    &mut self.output,
-                    &self.skip_move_check_fns,
-                )
+                self.check_fn_args_move_size(callee_ty, args, location);
+                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
             }
             mir::TerminatorKind::Drop { ref place, .. } => {
                 let ty = place.ty(self.body, self.tcx).ty;
@@ -797,7 +827,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                     match *op {
                         mir::InlineAsmOperand::SymFn { ref value } => {
                             let fn_ty = self.monomorphize(value.const_.ty());
-                            visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]);
+                            visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output);
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
@@ -835,16 +865,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
             push_mono_lang_item(self, reason.lang_item());
         }
 
+        self.visiting_call_terminator = matches!(terminator.kind, mir::TerminatorKind::Call { .. });
         self.super_terminator(terminator, location);
-        self.skip_move_size_check = false;
+        self.visiting_call_terminator = false;
     }
 
     fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
         self.super_operand(operand, location);
-        let move_size_limit = self.tcx.move_size_limit().0;
-        if move_size_limit > 0 && !self.skip_move_size_check {
-            self.check_move_size(move_size_limit, operand, location);
-        }
+        self.check_operand_move_size(operand, location);
     }
 
     fn visit_local(
@@ -873,11 +901,8 @@ fn visit_fn_use<'tcx>(
     is_direct_call: bool,
     source: Span,
     output: &mut MonoItems<'tcx>,
-    skip_move_check_fns: &[DefId],
-) -> bool {
-    let mut skip_move_size_check = false;
+) {
     if let ty::FnDef(def_id, args) = *ty.kind() {
-        skip_move_size_check = skip_move_check_fns.contains(&def_id);
         let instance = if is_direct_call {
             ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
         } else {
@@ -888,7 +913,6 @@ fn visit_fn_use<'tcx>(
         };
         visit_instance_use(tcx, instance, is_direct_call, source, output);
     }
-    skip_move_size_check
 }
 
 fn visit_instance_use<'tcx>(
@@ -1395,6 +1419,29 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
     return None;
 }
 
+fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
+    let mut skip_move_check_fns = vec![];
+    add_assoc_fn(
+        tcx,
+        tcx.lang_items().owned_box(),
+        Ident::from_str("new"),
+        &mut skip_move_check_fns,
+    );
+    add_assoc_fn(
+        tcx,
+        tcx.get_diagnostic_item(sym::Arc),
+        Ident::from_str("new"),
+        &mut skip_move_check_fns,
+    );
+    add_assoc_fn(
+        tcx,
+        tcx.get_diagnostic_item(sym::Rc),
+        Ident::from_str("new"),
+        &mut skip_move_check_fns,
+    );
+    skip_move_check_fns
+}
+
 /// Scans the MIR in order to find function calls, closures, and drop-glue.
 #[instrument(skip(tcx, output), level = "debug")]
 fn collect_used_items<'tcx>(
@@ -1404,28 +1451,6 @@ fn collect_used_items<'tcx>(
 ) {
     let body = tcx.instance_mir(instance.def);
 
-    let mut skip_move_check_fns = vec![];
-    if tcx.move_size_limit().0 > 0 {
-        add_assoc_fn(
-            tcx,
-            tcx.lang_items().owned_box(),
-            Ident::from_str("new"),
-            &mut skip_move_check_fns,
-        );
-        add_assoc_fn(
-            tcx,
-            tcx.get_diagnostic_item(sym::Arc),
-            Ident::from_str("new"),
-            &mut skip_move_check_fns,
-        );
-        add_assoc_fn(
-            tcx,
-            tcx.get_diagnostic_item(sym::Rc),
-            Ident::from_str("new"),
-            &mut skip_move_check_fns,
-        );
-    }
-
     // Here we rely on the visitor also visiting `required_consts`, so that we evaluate them
     // and abort compilation if any of them errors.
     MirUsedCollector {
@@ -1434,8 +1459,8 @@ fn collect_used_items<'tcx>(
         output,
         instance,
         move_size_spans: vec![],
-        skip_move_size_check: false,
-        skip_move_check_fns,
+        visiting_call_terminator: false,
+        skip_move_check_fns: None,
     }
     .visit_body(&body);
 }
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 07910113dee..1d9dbfe4b89 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -55,16 +55,14 @@ impl<'a> TokenTreesReader<'a> {
                     let (this_spacing, next_tok) = loop {
                         let (next_tok, is_next_tok_preceded_by_whitespace) =
                             self.string_reader.next_token();
-                        if !is_next_tok_preceded_by_whitespace {
-                            if let Some(glued) = self.token.glue(&next_tok) {
-                                self.token = glued;
-                            } else {
-                                let this_spacing =
-                                    if next_tok.is_op() { Spacing::Joint } else { Spacing::Alone };
-                                break (this_spacing, next_tok);
-                            }
-                        } else {
+                        if is_next_tok_preceded_by_whitespace {
                             break (Spacing::Alone, next_tok);
+                        } else if let Some(glued) = self.token.glue(&next_tok) {
+                            self.token = glued;
+                        } else {
+                            let this_spacing =
+                                if next_tok.is_punct() { Spacing::Joint } else { Spacing::Alone };
+                            break (this_spacing, next_tok);
                         }
                     };
                     let this_tok = std::mem::replace(&mut self.token, next_tok);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 91bb2d9eb66..1d883e16f9d 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1592,7 +1592,7 @@ impl<'a> Parser<'a> {
         } else if !ate_colon
             && self.may_recover()
             && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
-                || self.token.is_op())
+                || self.token.is_punct())
         {
             let (lit, _) =
                 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 90ac436a91f..7b6153eea09 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -9,6 +9,9 @@
     html_playground_url = "https://play.rust-lang.org/",
     test(attr(deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 // We want to be able to build this crate with a stable compiler, so no
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 214c6d70960..25ef5245cf1 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -580,6 +580,8 @@ passes_outside_loop =
         *[false] {""}
     }
 
+passes_outside_loop_suggestion = consider labeling this block to be able to break within it
+
 passes_params_not_allowed =
     referencing function parameters is not allowed in naked functions
     .help = follow the calling convention in asm block to use parameters
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 52fb193f3da..fbf3dff7560 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1108,6 +1108,7 @@ impl CheckAttrVisitor<'_> {
                         | 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;
@@ -1166,6 +1167,18 @@ impl CheckAttrVisitor<'_> {
                         | sym::plugins
                         | sym::fake_variadic => {}
 
+                        sym::rust_logo => {
+                            if !self.tcx.features().rustdoc_internals {
+                                feature_err(
+                                    &self.tcx.sess.parse_sess,
+                                    sym::rustdoc_internals,
+                                    meta.span(),
+                                    "the `#[doc(rust_logo)]` attribute is used for Rust branding",
+                                )
+                                .emit();
+                            }
+                        }
+
                         sym::test => {
                             if !self.check_test_attr(meta, hir_id) {
                                 is_valid = false;
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index bcf5abbfe7d..4b27b6d8c36 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1099,6 +1099,16 @@ pub struct OutsideLoop<'a> {
     pub span: Span,
     pub name: &'a str,
     pub is_break: bool,
+    #[subdiagnostic]
+    pub suggestion: Option<OutsideLoopSuggestion>,
+}
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")]
+pub struct OutsideLoopSuggestion {
+    #[suggestion_part(code = "'block: ")]
+    pub block_span: Span,
+    #[suggestion_part(code = " 'block")]
+    pub break_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 51f3c9ad76f..946a9e68da6 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,6 +6,9 @@
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 0aaf85086e4..4590ab9e4f5 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,7 +1,7 @@
 use Context::*;
 
 use rustc_hir as hir;
-use rustc_hir::def_id::LocalModDefId;
+use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Destination, Movability, Node};
 use rustc_middle::hir::map::Map;
@@ -10,19 +10,21 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
 
 use crate::errors::{
     BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
-    UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
+    OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
 };
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum Context {
     Normal,
+    Fn,
     Loop(hir::LoopSource),
     Closure(Span),
     AsyncClosure(Span),
+    UnlabeledBlock(Span),
     LabeledBlock,
     Constant,
 }
@@ -60,6 +62,25 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
         self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
     }
 
+    fn visit_fn(
+        &mut self,
+        fk: hir::intravisit::FnKind<'hir>,
+        fd: &'hir hir::FnDecl<'hir>,
+        b: hir::BodyId,
+        _: Span,
+        id: LocalDefId,
+    ) {
+        self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id));
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) {
+        self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item));
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) {
+        self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item));
+    }
+
     fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
         match e.kind {
             hir::ExprKind::Loop(ref b, _, source, _) => {
@@ -83,6 +104,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
             hir::ExprKind::Block(ref b, Some(_label)) => {
                 self.with_context(LabeledBlock, |v| v.visit_block(&b));
             }
+            hir::ExprKind::Block(ref b, None) if matches!(self.cx, Fn) => {
+                self.with_context(Normal, |v| v.visit_block(&b));
+            }
+            hir::ExprKind::Block(ref b, None)
+                if matches!(self.cx, Normal | Constant | UnlabeledBlock(_)) =>
+            {
+                self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(&b));
+            }
             hir::ExprKind::Break(break_label, ref opt_expr) => {
                 if let Some(e) = opt_expr {
                     self.visit_expr(e);
@@ -147,7 +176,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     }
                 }
 
-                self.require_break_cx("break", e.span);
+                let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32));
+                let label_sp = match break_label.label {
+                    Some(label) => sp_lo.with_hi(label.ident.span.hi()),
+                    None => sp_lo.shrink_to_lo(),
+                };
+                self.require_break_cx("break", e.span, label_sp);
             }
             hir::ExprKind::Continue(destination) => {
                 self.require_label_in_labeled_block(e.span, &destination, "continue");
@@ -169,7 +203,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     }
                     Err(_) => {}
                 }
-                self.require_break_cx("continue", e.span)
+                self.require_break_cx("continue", e.span, e.span)
             }
             _ => intravisit::walk_expr(self, e),
         }
@@ -187,7 +221,8 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
         self.cx = old_cx;
     }
 
-    fn require_break_cx(&self, name: &str, span: Span) {
+    fn require_break_cx(&self, name: &str, span: Span, break_span: Span) {
+        let is_break = name == "break";
         match self.cx {
             LabeledBlock | Loop(_) => {}
             Closure(closure_span) => {
@@ -196,8 +231,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             AsyncClosure(closure_span) => {
                 self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
             }
-            Normal | Constant => {
-                self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" });
+            UnlabeledBlock(block_span) if is_break && block_span.ctxt() == break_span.ctxt() => {
+                let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
+                self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion });
+            }
+            Normal | Constant | Fn | UnlabeledBlock(_) => {
+                self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion: None });
             }
         }
     }
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index faa7495ef9f..0e1c80a1f64 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -7,6 +7,9 @@
 //! of the Unstable Book for some examples.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ab85f680fcf..21d7bcbed5e 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,4 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_defaults)]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 30621a135eb..a1465dabed6 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -1,6 +1,8 @@
 //! Support for serializing the dep-graph and reloading it.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 // this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref
 #![feature(const_mut_refs)]
 #![feature(const_refs_to_cell)]
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 949c6ab5ac0..0bc45967e3d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -7,6 +7,8 @@
 //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(extract_if)]
@@ -1074,8 +1076,8 @@ 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 enabled for this crate.
-    active_features: FxHashSet<Symbol>,
+    /// Features declared for this crate.
+    declared_features: FxHashSet<Symbol>,
 
     lint_buffer: LintBuffer,
 
@@ -1417,12 +1419,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             multi_segment_macro_resolutions: Default::default(),
             builtin_attrs: Default::default(),
             containers_deriving_copy: Default::default(),
-            active_features: features
-                .declared_lib_features
-                .iter()
-                .map(|(feat, ..)| *feat)
-                .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
-                .collect(),
+            declared_features: features.declared_features.clone(),
             lint_buffer: LintBuffer::default(),
             next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 90ae08ce37c..f0a1a4ff931 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -854,7 +854,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let feature = stability.feature;
 
                 let is_allowed = |feature| {
-                    self.active_features.contains(&feature) || span.allows_unstable(feature)
+                    self.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 {
diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs
deleted file mode 100644
index 8f8c504117c..00000000000
--- a/compiler/rustc_serialize/src/collection_impls.rs
+++ /dev/null
@@ -1,279 +0,0 @@
-//! Implementations of serialization for structures found in liballoc
-
-use crate::{Decodable, Decoder, Encodable, Encoder};
-use smallvec::{Array, SmallVec};
-use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList, VecDeque};
-use std::hash::{BuildHasher, Hash};
-use std::rc::Rc;
-use std::sync::Arc;
-use thin_vec::ThinVec;
-
-impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
-    fn encode(&self, s: &mut S) {
-        let slice: &[A::Item] = self;
-        slice.encode(s);
-    }
-}
-
-impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> {
-    fn decode(d: &mut D) -> SmallVec<A> {
-        let len = d.read_usize();
-        (0..len).map(|_| Decodable::decode(d)).collect()
-    }
-}
-
-impl<S: Encoder, T: Encodable<S>> Encodable<S> for ThinVec<T> {
-    fn encode(&self, s: &mut S) {
-        self.as_slice().encode(s);
-    }
-}
-
-impl<D: Decoder, T: Decodable<D>> Decodable<D> for ThinVec<T> {
-    fn decode(d: &mut D) -> ThinVec<T> {
-        let len = d.read_usize();
-        (0..len).map(|_| Decodable::decode(d)).collect()
-    }
-}
-
-impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
-    fn encode(&self, s: &mut S) {
-        s.emit_usize(self.len());
-        for e in self.iter() {
-            e.encode(s);
-        }
-    }
-}
-
-impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> {
-    fn decode(d: &mut D) -> LinkedList<T> {
-        let len = d.read_usize();
-        (0..len).map(|_| Decodable::decode(d)).collect()
-    }
-}
-
-impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
-    fn encode(&self, s: &mut S) {
-        s.emit_usize(self.len());
-        for e in self.iter() {
-            e.encode(s);
-        }
-    }
-}
-
-impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> {
-    fn decode(d: &mut D) -> VecDeque<T> {
-        let len = d.read_usize();
-        (0..len).map(|_| Decodable::decode(d)).collect()
-    }
-}
-
-impl<S: Encoder, K, V> Encodable<S> for BTreeMap<K, V>
-where
-    K: Encodable<S> + PartialEq + Ord,
-    V: Encodable<S>,
-{
-    fn encode(&self, e: &mut S) {
-        e.emit_usize(self.len());
-        for (key, val) in self.iter() {
-            key.encode(e);
-            val.encode(e);
-        }
-    }
-}
-
-impl<D: Decoder, K, V> Decodable<D> for BTreeMap<K, V>
-where
-    K: Decodable<D> + PartialEq + Ord,
-    V: Decodable<D>,
-{
-    fn decode(d: &mut D) -> BTreeMap<K, V> {
-        let len = d.read_usize();
-        let mut map = BTreeMap::new();
-        for _ in 0..len {
-            let key = Decodable::decode(d);
-            let val = Decodable::decode(d);
-            map.insert(key, val);
-        }
-        map
-    }
-}
-
-impl<S: Encoder, T> Encodable<S> for BTreeSet<T>
-where
-    T: Encodable<S> + PartialEq + Ord,
-{
-    fn encode(&self, s: &mut S) {
-        s.emit_usize(self.len());
-        for e in self.iter() {
-            e.encode(s);
-        }
-    }
-}
-
-impl<D: Decoder, T> Decodable<D> for BTreeSet<T>
-where
-    T: Decodable<D> + PartialEq + Ord,
-{
-    fn decode(d: &mut D) -> BTreeSet<T> {
-        let len = d.read_usize();
-        let mut set = BTreeSet::new();
-        for _ in 0..len {
-            set.insert(Decodable::decode(d));
-        }
-        set
-    }
-}
-
-impl<E: Encoder, K, V, S> Encodable<E> for HashMap<K, V, S>
-where
-    K: Encodable<E> + Eq,
-    V: Encodable<E>,
-    S: BuildHasher,
-{
-    fn encode(&self, e: &mut E) {
-        e.emit_usize(self.len());
-        for (key, val) in self.iter() {
-            key.encode(e);
-            val.encode(e);
-        }
-    }
-}
-
-impl<D: Decoder, K, V, S> Decodable<D> for HashMap<K, V, S>
-where
-    K: Decodable<D> + Hash + Eq,
-    V: Decodable<D>,
-    S: BuildHasher + Default,
-{
-    fn decode(d: &mut D) -> HashMap<K, V, S> {
-        let len = d.read_usize();
-        let state = Default::default();
-        let mut map = HashMap::with_capacity_and_hasher(len, state);
-        for _ in 0..len {
-            let key = Decodable::decode(d);
-            let val = Decodable::decode(d);
-            map.insert(key, val);
-        }
-        map
-    }
-}
-
-impl<E: Encoder, T, S> Encodable<E> for HashSet<T, S>
-where
-    T: Encodable<E> + Eq,
-    S: BuildHasher,
-{
-    fn encode(&self, s: &mut E) {
-        s.emit_usize(self.len());
-        for e in self.iter() {
-            e.encode(s);
-        }
-    }
-}
-
-impl<D: Decoder, T, S> Decodable<D> for HashSet<T, S>
-where
-    T: Decodable<D> + Hash + Eq,
-    S: BuildHasher + Default,
-{
-    fn decode(d: &mut D) -> HashSet<T, S> {
-        let len = d.read_usize();
-        let state = Default::default();
-        let mut set = HashSet::with_capacity_and_hasher(len, state);
-        for _ in 0..len {
-            set.insert(Decodable::decode(d));
-        }
-        set
-    }
-}
-
-impl<E: Encoder, K, V, S> Encodable<E> for indexmap::IndexMap<K, V, S>
-where
-    K: Encodable<E> + Hash + Eq,
-    V: Encodable<E>,
-    S: BuildHasher,
-{
-    fn encode(&self, e: &mut E) {
-        e.emit_usize(self.len());
-        for (key, val) in self.iter() {
-            key.encode(e);
-            val.encode(e);
-        }
-    }
-}
-
-impl<D: Decoder, K, V, S> Decodable<D> for indexmap::IndexMap<K, V, S>
-where
-    K: Decodable<D> + Hash + Eq,
-    V: Decodable<D>,
-    S: BuildHasher + Default,
-{
-    fn decode(d: &mut D) -> indexmap::IndexMap<K, V, S> {
-        let len = d.read_usize();
-        let state = Default::default();
-        let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
-        for _ in 0..len {
-            let key = Decodable::decode(d);
-            let val = Decodable::decode(d);
-            map.insert(key, val);
-        }
-        map
-    }
-}
-
-impl<E: Encoder, T, S> Encodable<E> for indexmap::IndexSet<T, S>
-where
-    T: Encodable<E> + Hash + Eq,
-    S: BuildHasher,
-{
-    fn encode(&self, s: &mut E) {
-        s.emit_usize(self.len());
-        for e in self.iter() {
-            e.encode(s);
-        }
-    }
-}
-
-impl<D: Decoder, T, S> Decodable<D> for indexmap::IndexSet<T, S>
-where
-    T: Decodable<D> + Hash + Eq,
-    S: BuildHasher + Default,
-{
-    fn decode(d: &mut D) -> indexmap::IndexSet<T, S> {
-        let len = d.read_usize();
-        let state = Default::default();
-        let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
-        for _ in 0..len {
-            set.insert(Decodable::decode(d));
-        }
-        set
-    }
-}
-
-impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
-    fn encode(&self, s: &mut E) {
-        let slice: &[T] = self;
-        slice.encode(s);
-    }
-}
-
-impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
-    fn decode(d: &mut D) -> Rc<[T]> {
-        let vec: Vec<T> = Decodable::decode(d);
-        vec.into()
-    }
-}
-
-impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
-    fn encode(&self, s: &mut E) {
-        let slice: &[T] = self;
-        slice.encode(s);
-    }
-}
-
-impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
-    fn decode(d: &mut D) -> Arc<[T]> {
-        let vec: Vec<T> = Decodable::decode(d);
-        vec.into()
-    }
-}
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index dd40b3cf028..cfa54072eb9 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -1,25 +1,22 @@
 //! Support code for encoding and decoding types.
 
-/*
-Core encoding and decoding interfaces.
-*/
-
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     html_playground_url = "https://play.rust-lang.org/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
-#![feature(never_type)]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![feature(allocator_api)]
 #![feature(associated_type_bounds)]
-#![feature(min_specialization)]
+#![feature(const_option)]
 #![feature(core_intrinsics)]
-#![feature(maybe_uninit_slice)]
-#![feature(new_uninit)]
-#![feature(allocator_api)]
+#![feature(inline_const)]
+#![feature(min_specialization)]
+#![feature(never_type)]
 #![feature(ptr_sub_ptr)]
 #![feature(slice_first_last_chunk)]
-#![feature(inline_const)]
-#![feature(const_option)]
 #![cfg_attr(test, feature(test))]
 #![allow(rustc::internal)]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -27,7 +24,6 @@ Core encoding and decoding interfaces.
 
 pub use self::serialize::{Decodable, Decoder, Encodable, Encoder};
 
-mod collection_impls;
 mod serialize;
 
 pub mod leb128;
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 06166cabc18..63bd3457eb9 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -1,12 +1,15 @@
 //! Support code for encoding and decoding types.
 
-use std::alloc::Allocator;
+use smallvec::{Array, SmallVec};
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
+use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
+use std::hash::{BuildHasher, Hash};
 use std::marker::PhantomData;
 use std::path;
 use std::rc::Rc;
 use std::sync::Arc;
+use thin_vec::ThinVec;
 
 /// A byte that [cannot occur in UTF8 sequences][utf8]. Used to mark the end of a string.
 /// This way we can skip validation and still be relatively sure that deserialization
@@ -273,9 +276,9 @@ impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
     }
 }
 
-impl<D: Decoder, A: Allocator + Default, T: Decodable<D>> Decodable<D> for Box<[T], A> {
-    fn decode(d: &mut D) -> Box<[T], A> {
-        let v: Vec<T, A> = Decodable::decode(d);
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> {
+    fn decode(d: &mut D) -> Box<[T]> {
+        let v: Vec<T> = Decodable::decode(d);
         v.into_boxed_slice()
     }
 }
@@ -303,33 +306,20 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
     fn encode(&self, s: &mut S) {
-        let slice: &[T] = self;
-        slice.encode(s);
+        self.as_slice().encode(s);
     }
 }
 
-impl<D: Decoder, T: Decodable<D>, A: Allocator + Default> Decodable<D> for Vec<T, A> {
-    default fn decode(d: &mut D) -> Vec<T, A> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
+    default fn decode(d: &mut D) -> Vec<T> {
         let len = d.read_usize();
-        let allocator = A::default();
-        // SAFETY: we set the capacity in advance, only write elements, and
-        // only set the length at the end once the writing has succeeded.
-        let mut vec = Vec::with_capacity_in(len, allocator);
-        unsafe {
-            let ptr: *mut T = vec.as_mut_ptr();
-            for i in 0..len {
-                std::ptr::write(ptr.add(i), Decodable::decode(d));
-            }
-            vec.set_len(len);
-        }
-        vec
+        (0..len).map(|_| Decodable::decode(d)).collect()
     }
 }
 
 impl<S: Encoder, T: Encodable<S>, const N: usize> Encodable<S> for [T; N] {
     fn encode(&self, s: &mut S) {
-        let slice: &[T] = self;
-        slice.encode(s);
+        self.as_slice().encode(s);
     }
 }
 
@@ -497,15 +487,233 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> {
     }
 }
 
-impl<S: Encoder, T: ?Sized + Encodable<S>, A: Allocator + Default> Encodable<S> for Box<T, A> {
+impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> {
     fn encode(&self, s: &mut S) {
         (**self).encode(s)
     }
 }
 
-impl<D: Decoder, A: Allocator + Default, T: Decodable<D>> Decodable<D> for Box<T, A> {
-    fn decode(d: &mut D) -> Box<T, A> {
-        let allocator = A::default();
-        Box::new_in(Decodable::decode(d), allocator)
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
+    fn decode(d: &mut D) -> Box<T> {
+        Box::new(Decodable::decode(d))
+    }
+}
+
+impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
+    fn encode(&self, s: &mut S) {
+        self.as_slice().encode(s);
+    }
+}
+
+impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> {
+    fn decode(d: &mut D) -> SmallVec<A> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for ThinVec<T> {
+    fn encode(&self, s: &mut S) {
+        self.as_slice().encode(s);
+    }
+}
+
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for ThinVec<T> {
+    fn decode(d: &mut D) -> ThinVec<T> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
+    }
+}
+
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> {
+    fn decode(d: &mut D) -> VecDeque<T> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
+impl<S: Encoder, K, V> Encodable<S> for BTreeMap<K, V>
+where
+    K: Encodable<S> + PartialEq + Ord,
+    V: Encodable<S>,
+{
+    fn encode(&self, e: &mut S) {
+        e.emit_usize(self.len());
+        for (key, val) in self.iter() {
+            key.encode(e);
+            val.encode(e);
+        }
+    }
+}
+
+impl<D: Decoder, K, V> Decodable<D> for BTreeMap<K, V>
+where
+    K: Decodable<D> + PartialEq + Ord,
+    V: Decodable<D>,
+{
+    fn decode(d: &mut D) -> BTreeMap<K, V> {
+        let len = d.read_usize();
+        (0..len).map(|_| (Decodable::decode(d), Decodable::decode(d))).collect()
+    }
+}
+
+impl<S: Encoder, T> Encodable<S> for BTreeSet<T>
+where
+    T: Encodable<S> + PartialEq + Ord,
+{
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
+    }
+}
+
+impl<D: Decoder, T> Decodable<D> for BTreeSet<T>
+where
+    T: Decodable<D> + PartialEq + Ord,
+{
+    fn decode(d: &mut D) -> BTreeSet<T> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
+impl<E: Encoder, K, V, S> Encodable<E> for HashMap<K, V, S>
+where
+    K: Encodable<E> + Eq,
+    V: Encodable<E>,
+    S: BuildHasher,
+{
+    fn encode(&self, e: &mut E) {
+        e.emit_usize(self.len());
+        for (key, val) in self.iter() {
+            key.encode(e);
+            val.encode(e);
+        }
+    }
+}
+
+impl<D: Decoder, K, V, S> Decodable<D> for HashMap<K, V, S>
+where
+    K: Decodable<D> + Hash + Eq,
+    V: Decodable<D>,
+    S: BuildHasher + Default,
+{
+    fn decode(d: &mut D) -> HashMap<K, V, S> {
+        let len = d.read_usize();
+        (0..len).map(|_| (Decodable::decode(d), Decodable::decode(d))).collect()
+    }
+}
+
+impl<E: Encoder, T, S> Encodable<E> for HashSet<T, S>
+where
+    T: Encodable<E> + Eq,
+    S: BuildHasher,
+{
+    fn encode(&self, s: &mut E) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
+    }
+}
+
+impl<D: Decoder, T, S> Decodable<D> for HashSet<T, S>
+where
+    T: Decodable<D> + Hash + Eq,
+    S: BuildHasher + Default,
+{
+    fn decode(d: &mut D) -> HashSet<T, S> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
+impl<E: Encoder, K, V, S> Encodable<E> for indexmap::IndexMap<K, V, S>
+where
+    K: Encodable<E> + Hash + Eq,
+    V: Encodable<E>,
+    S: BuildHasher,
+{
+    fn encode(&self, e: &mut E) {
+        e.emit_usize(self.len());
+        for (key, val) in self.iter() {
+            key.encode(e);
+            val.encode(e);
+        }
+    }
+}
+
+impl<D: Decoder, K, V, S> Decodable<D> for indexmap::IndexMap<K, V, S>
+where
+    K: Decodable<D> + Hash + Eq,
+    V: Decodable<D>,
+    S: BuildHasher + Default,
+{
+    fn decode(d: &mut D) -> indexmap::IndexMap<K, V, S> {
+        let len = d.read_usize();
+        (0..len).map(|_| (Decodable::decode(d), Decodable::decode(d))).collect()
+    }
+}
+
+impl<E: Encoder, T, S> Encodable<E> for indexmap::IndexSet<T, S>
+where
+    T: Encodable<E> + Hash + Eq,
+    S: BuildHasher,
+{
+    fn encode(&self, s: &mut E) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
+    }
+}
+
+impl<D: Decoder, T, S> Decodable<D> for indexmap::IndexSet<T, S>
+where
+    T: Decodable<D> + Hash + Eq,
+    S: BuildHasher + Default,
+{
+    fn decode(d: &mut D) -> indexmap::IndexSet<T, S> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
+impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
+    fn encode(&self, s: &mut E) {
+        let slice: &[T] = self;
+        slice.encode(s);
+    }
+}
+
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
+    fn decode(d: &mut D) -> Rc<[T]> {
+        let vec: Vec<T> = Decodable::decode(d);
+        vec.into()
+    }
+}
+
+impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
+    fn encode(&self, s: &mut E) {
+        let slice: &[T] = self;
+        slice.encode(s);
+    }
+}
+
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
+    fn decode(d: &mut D) -> Arc<[T]> {
+        let vec: Vec<T> = Decodable::decode(d);
+        vec.into()
     }
 }
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index e26d25d9a41..3af83aaaaa8 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-bitflags = "1.2.1"
 getopts = "0.2"
 rustc_macros = { path = "../rustc_macros" }
 tracing = "0.1"
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e120f595d92..58461856eb1 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -12,6 +12,7 @@ use crate::{EarlyErrorHandler, Session};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
 use rustc_target::abi::Align;
+use rustc_target::spec::LinkSelfContainedComponents;
 use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo};
 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
 
@@ -232,63 +233,35 @@ pub struct LinkSelfContained {
     /// Used for compatibility with the existing opt-in and target inference.
     pub explicitly_set: Option<bool>,
 
-    /// The components that are enabled.
-    components: LinkSelfContainedComponents,
-}
-
-bitflags::bitflags! {
-    #[derive(Default)]
-    /// The `-C link-self-contained` components that can individually be enabled or disabled.
-    pub struct LinkSelfContainedComponents: u8 {
-        /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets)
-        const CRT_OBJECTS = 1 << 0;
-        /// libc static library (e.g. on `musl`, `wasi` targets)
-        const LIBC        = 1 << 1;
-        /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
-        const UNWIND      = 1 << 2;
-        /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
-        const LINKER      = 1 << 3;
-        /// Sanitizer runtime libraries
-        const SANITIZERS  = 1 << 4;
-        /// Other MinGW libs and Windows import libs
-        const MINGW       = 1 << 5;
-    }
-}
-
-impl FromStr for LinkSelfContainedComponents {
-    type Err = ();
+    /// The components that are enabled on the CLI, using the `+component` syntax or one of the
+    /// `true` shorcuts.
+    enabled_components: LinkSelfContainedComponents,
 
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        Ok(match s {
-            "crto" => LinkSelfContainedComponents::CRT_OBJECTS,
-            "libc" => LinkSelfContainedComponents::LIBC,
-            "unwind" => LinkSelfContainedComponents::UNWIND,
-            "linker" => LinkSelfContainedComponents::LINKER,
-            "sanitizers" => LinkSelfContainedComponents::SANITIZERS,
-            "mingw" => LinkSelfContainedComponents::MINGW,
-            _ => return Err(()),
-        })
-    }
+    /// The components that are disabled on the CLI, using the `-component` syntax or one of the
+    /// `false` shortcuts.
+    disabled_components: LinkSelfContainedComponents,
 }
 
 impl LinkSelfContained {
     /// Incorporates an enabled or disabled component as specified on the CLI, if possible.
     /// For example: `+linker`, and `-crto`.
-    pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> {
+    pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> {
         // Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit
         // set of all values like `y` or `n` used to be. Therefore, if this flag had previously been
         // set in bulk with its historical values, then manually setting a component clears that
         // `explicitly_set` state.
         if let Some(component_to_enable) = component.strip_prefix('+') {
             self.explicitly_set = None;
-            self.components.insert(component_to_enable.parse()?);
-            Ok(())
+            self.enabled_components
+                .insert(LinkSelfContainedComponents::from_str(component_to_enable)?);
+            Some(())
         } else if let Some(component_to_disable) = component.strip_prefix('-') {
             self.explicitly_set = None;
-            self.components.remove(component_to_disable.parse()?);
-            Ok(())
+            self.disabled_components
+                .insert(LinkSelfContainedComponents::from_str(component_to_disable)?);
+            Some(())
         } else {
-            Err(())
+            None
         }
     }
 
@@ -296,11 +269,14 @@ impl LinkSelfContained {
     /// purposes.
     pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
         self.explicitly_set = Some(enabled);
-        self.components = if enabled {
-            LinkSelfContainedComponents::all()
+
+        if enabled {
+            self.enabled_components = LinkSelfContainedComponents::all();
+            self.disabled_components = LinkSelfContainedComponents::empty();
         } else {
-            LinkSelfContainedComponents::empty()
-        };
+            self.enabled_components = LinkSelfContainedComponents::empty();
+            self.disabled_components = LinkSelfContainedComponents::all();
+        }
     }
 
     /// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests.
@@ -314,13 +290,32 @@ impl LinkSelfContained {
     /// components was set individually. This would also require the `-Zunstable-options` flag, to
     /// be allowed.
     fn are_unstable_variants_set(&self) -> bool {
-        let any_component_set = !self.components.is_empty();
+        let any_component_set =
+            !self.enabled_components.is_empty() || !self.disabled_components.is_empty();
         self.explicitly_set.is_none() && any_component_set
     }
 
-    /// Returns whether the self-contained linker component is enabled.
-    pub fn linker(&self) -> bool {
-        self.components.contains(LinkSelfContainedComponents::LINKER)
+    /// Returns whether the self-contained linker component was enabled on the CLI, using the
+    /// `-C link-self-contained=+linker` syntax, or one of the `true` shorcuts.
+    pub fn is_linker_enabled(&self) -> bool {
+        self.enabled_components.contains(LinkSelfContainedComponents::LINKER)
+    }
+
+    /// Returns whether the self-contained linker component was disabled on the CLI, using the
+    /// `-C link-self-contained=-linker` syntax, or one of the `false` shorcuts.
+    pub fn is_linker_disabled(&self) -> bool {
+        self.disabled_components.contains(LinkSelfContainedComponents::LINKER)
+    }
+
+    /// Returns CLI inconsistencies to emit errors: individual components were both enabled and
+    /// disabled.
+    fn check_consistency(&self) -> Option<LinkSelfContainedComponents> {
+        if self.explicitly_set.is_some() {
+            None
+        } else {
+            let common = self.enabled_components.intersection(self.disabled_components);
+            if common.is_empty() { None } else { Some(common) }
+        }
     }
 }
 
@@ -2758,9 +2753,8 @@ pub fn build_session_options(
     }
 
     // For testing purposes, until we have more feedback about these options: ensure `-Z
-    // unstable-options` is required when using the unstable `-C link-self-contained` options, like
-    // `-C link-self-contained=+linker`, and when using the unstable `-C linker-flavor` options, like
-    // `-C linker-flavor=gnu-lld-cc`.
+    // unstable-options` is required when using the unstable `-C link-self-contained` and `-C
+    // linker-flavor` options.
     if !nightly_options::is_unstable_enabled(matches) {
         let uses_unstable_self_contained_option =
             cg.link_self_contained.are_unstable_variants_set();
@@ -2782,6 +2776,19 @@ pub fn build_session_options(
         }
     }
 
+    // Check `-C link-self-contained` for consistency: individual components cannot be both enabled
+    // and disabled at the same time.
+    if let Some(erroneous_components) = cg.link_self_contained.check_consistency() {
+        let names: String = erroneous_components
+            .into_iter()
+            .map(|c| c.as_str().unwrap())
+            .intersperse(", ")
+            .collect();
+        handler.early_error(format!(
+            "some `-C link-self-contained` components were both enabled and disabled: {names}"
+        ));
+    }
+
     let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches);
 
     let cg = cg;
@@ -3165,11 +3172,12 @@ impl PpMode {
 /// 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 super::Polonius;
     use super::{
         BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
-        ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto,
-        LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
-        Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
+        ErrorOutputType, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
+        LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes,
+        ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
         SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
     };
     use crate::lint;
@@ -3266,7 +3274,6 @@ pub(crate) mod dep_tracking {
         SymbolManglingVersion,
         SourceFileHashAlgorithm,
         TrimmedDefPaths,
-        Option<LdImpl>,
         OutFileName,
         OutputType,
         RealFileName,
@@ -3275,6 +3282,7 @@ pub(crate) mod dep_tracking {
         OomStrategy,
         LanguageIdentifier,
         TraitSolver,
+        Polonius,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
@@ -3413,3 +3421,35 @@ impl DumpMonoStatsFormat {
         }
     }
 }
+
+/// `-Zpolonius` values, enabling the borrow checker polonius analysis, and which version: legacy,
+/// or future prototype.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum Polonius {
+    /// The default value: disabled.
+    Off,
+
+    /// Legacy version, using datalog and the `polonius-engine` crate. Historical value for `-Zpolonius`.
+    Legacy,
+
+    /// In-tree prototype, extending the NLL infrastructure.
+    Next,
+}
+
+impl Default for Polonius {
+    fn default() -> Self {
+        Polonius::Off
+    }
+}
+
+impl Polonius {
+    /// Returns whether the legacy version of polonius is enabled
+    pub fn is_legacy_enabled(&self) -> bool {
+        matches!(self, Polonius::Legacy)
+    }
+
+    /// Returns whether the "next" version of polonius is enabled
+    pub fn is_next_enabled(&self) -> bool {
+        matches!(self, Polonius::Next)
+    }
+}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index d6c746a7bd8..ed6705ec239 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(option_get_or_insert_default)]
 #![feature(rustc_attrs)]
 #![feature(map_many_mut)]
+#![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c1424db600e..eb1aa6d6c88 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -412,9 +412,9 @@ mod desc {
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
     pub const parse_split_dwarf_kind: &str =
         "one of supported split dwarf modes (`split` or `single`)";
-    pub const parse_gcc_ld: &str = "one of: no value, `lld`";
     pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \
         components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`";
+    pub const parse_polonius: &str = "either no value or `legacy` (the default), or `next`";
     pub const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
     pub const parse_branch_protection: &str =
@@ -472,6 +472,21 @@ mod parse {
         }
     }
 
+    /// Parses whether polonius is enabled, and if so, which version.
+    pub(crate) fn parse_polonius(slot: &mut Polonius, v: Option<&str>) -> bool {
+        match v {
+            Some("legacy") | None => {
+                *slot = Polonius::Legacy;
+                true
+            }
+            Some("next") => {
+                *slot = Polonius::Next;
+                true
+            }
+            _ => false,
+        }
+    }
+
     /// Use this for any string option that has a static default.
     pub(crate) fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
         match v {
@@ -1166,7 +1181,7 @@ mod parse {
 
         // 2. Parse a list of enabled and disabled components.
         for comp in s.split(',') {
-            if slot.handle_cli_component(comp).is_err() {
+            if slot.handle_cli_component(comp).is_none() {
                 return false;
             }
         }
@@ -1202,15 +1217,6 @@ mod parse {
         true
     }
 
-    pub(crate) fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
-        match v {
-            None => *slot = None,
-            Some("lld") => *slot = Some(LdImpl::Lld),
-            _ => return false,
-        }
-        true
-    }
-
     pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
         match v.and_then(|s| StackProtector::from_str(s).ok()) {
             Some(ssp) => *slot = ssp,
@@ -1521,7 +1527,6 @@ options! {
         "whether each function should go in its own section"),
     future_incompat_test: bool = (false, parse_bool, [UNTRACKED],
         "forces all lints to be future incompatible, used for internal testing (default: no)"),
-    gcc_ld: Option<LdImpl> = (None, parse_gcc_ld, [TRACKED], "implementation of ld used by cc"),
     graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED],
         "use dark-themed colors in graphviz output (default: no)"),
     graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
@@ -1610,9 +1615,10 @@ options! {
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
     mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
-        "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the specified passes to be \
-        enabled, overriding all other checks. Passes that are not specified are enabled or \
-        disabled by other flags as usual."),
+        "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \
+        specified passes to be enabled, overriding all other checks. In particular, this will \
+        enable unsound (known-buggy and hence usually disabled) passes without further warning! \
+        Passes that are not specified are enabled or disabled by other flags as usual."),
     mir_include_spans: bool = (false, parse_bool, [UNTRACKED],
         "use line numbers relative to the function in mir pretty printing"),
     mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
@@ -1669,7 +1675,7 @@ options! {
         "whether to use the PLT when calling into shared libraries;
         only has effect for PIC code on systems with ELF binaries
         (default: PLT is disabled if full relro is enabled on x86_64)"),
-    polonius: bool = (false, parse_bool, [TRACKED],
+    polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
         "enable polonius-based borrow-checker (default: no)"),
     polymorphize: bool = (false, parse_bool, [TRACKED],
           "perform polymorphization analysis"),
@@ -1906,8 +1912,3 @@ pub enum WasiExecModel {
     Command,
     Reactor,
 }
-
-#[derive(Clone, Copy, Hash)]
-pub enum LdImpl {
-    Lld,
-}
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml
index 3e0d6baab6a..2b77044d6bf 100644
--- a/compiler/rustc_smir/Cargo.toml
+++ b/compiler/rustc_smir/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
+rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_driver = { path = "../rustc_driver" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_interface = { path = "../rustc_interface" }
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index d10f46fad9e..c24b9efe865 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -10,6 +10,9 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 pub mod rustc_internal;
 
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 36eb2247253..e3c84f06543 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,24 +3,27 @@
 //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
 //! until stable MIR is complete.
 
-use std::ops::{ControlFlow, Index};
-
 use crate::rustc_internal;
 use crate::rustc_smir::Tables;
+use rustc_data_structures::fx;
 use rustc_driver::{Callbacks, Compilation, RunCompiler};
 use rustc_interface::{interface, Queries};
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
+use stable_mir::ty::IndexedVal;
 use stable_mir::CompilerError;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::ops::{ControlFlow, Index};
 
 impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
     type Output = DefId;
 
     #[inline(always)]
     fn index(&self, index: stable_mir::DefId) -> &Self::Output {
-        &self.def_ids[index.0]
+        &self.def_ids[index]
     }
 }
 
@@ -29,7 +32,7 @@ impl<'tcx> Index<stable_mir::ty::Span> for Tables<'tcx> {
 
     #[inline(always)]
     fn index(&self, index: stable_mir::ty::Span) -> &Self::Output {
-        &self.spans[index.0]
+        &self.spans[index]
     }
 }
 
@@ -95,36 +98,15 @@ impl<'tcx> Tables<'tcx> {
     }
 
     fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
-        // FIXME: this becomes inefficient when we have too many ids
-        for (i, &d) in self.def_ids.iter().enumerate() {
-            if d == did {
-                return stable_mir::DefId(i);
-            }
-        }
-        let id = self.def_ids.len();
-        self.def_ids.push(did);
-        stable_mir::DefId(id)
+        self.def_ids.create_or_fetch(did)
     }
 
     fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::AllocId {
-        // FIXME: this becomes inefficient when we have too many ids
-        if let Some(i) = self.alloc_ids.iter().position(|a| *a == aid) {
-            return stable_mir::AllocId(i);
-        };
-        let id = self.def_ids.len();
-        self.alloc_ids.push(aid);
-        stable_mir::AllocId(id)
+        self.alloc_ids.create_or_fetch(aid)
     }
 
     pub(crate) fn create_span(&mut self, span: Span) -> stable_mir::ty::Span {
-        for (i, &sp) in self.spans.iter().enumerate() {
-            if sp == span {
-                return stable_mir::ty::Span(i);
-            }
-        }
-        let id = self.spans.len();
-        self.spans.push(span);
-        stable_mir::ty::Span(id)
+        self.spans.create_or_fetch(span)
     }
 }
 
@@ -134,7 +116,13 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
 
 pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
     stable_mir::run(
-        Tables { tcx, def_ids: vec![], alloc_ids: vec![], spans: vec![], types: vec![] },
+        Tables {
+            tcx,
+            def_ids: rustc_internal::IndexMap { index_map: fx::FxIndexMap::default() },
+            alloc_ids: rustc_internal::IndexMap { index_map: fx::FxIndexMap::default() },
+            spans: rustc_internal::IndexMap { index_map: fx::FxIndexMap::default() },
+            types: vec![],
+        },
         f,
     );
 }
@@ -197,3 +185,29 @@ where
         })
     }
 }
+
+/// Simmilar to rustc's `FxIndexMap`, `IndexMap` with extra
+/// safety features added.
+pub struct IndexMap<K, V> {
+    index_map: fx::FxIndexMap<K, V>,
+}
+
+impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> IndexMap<K, V> {
+    pub fn create_or_fetch(&mut self, key: K) -> V {
+        let len = self.index_map.len();
+        let v = self.index_map.entry(key).or_insert(V::to_val(len));
+        *v
+    }
+}
+
+impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V>
+    for IndexMap<K, V>
+{
+    type Output = K;
+
+    fn index(&self, index: V) -> &Self::Output {
+        let (k, v) = self.index_map.get_index(index.to_index()).unwrap();
+        assert_eq!(*v, index, "Provided value doesn't match with indexed value");
+        k
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 7d1122c2fd2..2a265fc1f5b 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,6 +7,7 @@
 //!
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
+use crate::rustc_internal::IndexMap;
 use crate::rustc_smir::hir::def::DefKind;
 use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region};
 use rustc_hir as hir;
@@ -31,11 +32,18 @@ impl<'tcx> Context for Tables<'tcx> {
         self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
     }
 
-    fn find_crate(&self, name: &str) -> Option<stable_mir::Crate> {
-        [LOCAL_CRATE].iter().chain(self.tcx.crates(()).iter()).find_map(|crate_num| {
-            let crate_name = self.tcx.crate_name(*crate_num).to_string();
-            (name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
-        })
+    fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
+        let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
+            .iter()
+            .chain(self.tcx.crates(()).iter())
+            .map(|crate_num| {
+                let crate_name = self.tcx.crate_name(*crate_num).to_string();
+                (name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
+            })
+            .into_iter()
+            .filter_map(|c| c)
+            .collect();
+        crates
     }
 
     fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
@@ -194,9 +202,9 @@ impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
 
 pub struct Tables<'tcx> {
     pub tcx: TyCtxt<'tcx>,
-    pub def_ids: Vec<DefId>,
-    pub alloc_ids: Vec<AllocId>,
-    pub spans: Vec<rustc_span::Span>,
+    pub def_ids: IndexMap<DefId, stable_mir::DefId>,
+    pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
+    pub spans: IndexMap<rustc_span::Span, Span>,
     pub types: Vec<MaybeStable<stable_mir::ty::TyKind, Ty<'tcx>>>,
 }
 
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 6fd61e45fcc..e62efab5793 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -14,6 +14,8 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(array_windows)]
 #![feature(if_let_guard)]
 #![feature(negative_impls)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index a62fa246ac4..ea261923c65 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1327,6 +1327,7 @@ symbols! {
         rust_cold_cc,
         rust_eh_catch_typeinfo,
         rust_eh_personality,
+        rust_logo,
         rustc,
         rustc_abi,
         rustc_allocator,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 535a3ea2d7e..6ade2d777c7 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -88,6 +88,9 @@
 //! DefPaths which are much more robust in the face of changes to the code base.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index e838e11131f..9c5ce889418 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -8,6 +8,8 @@
 //! LLVM.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 1bcb1f35315..16f70cf43b3 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -164,11 +164,11 @@ pub enum LinkerFlavor {
 
 /// Linker flavors available externally through command line (`-Clinker-flavor`)
 /// or json target specifications.
-/// FIXME: This set has accumulated historically, bring it more in line with the internal
-/// linker flavors (`LinkerFlavor`).
+/// This set has accumulated historically, and contains both (stable and unstable) legacy values, as
+/// well as modern ones matching the internal linker flavors (`LinkerFlavor`).
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
 pub enum LinkerFlavorCli {
-    // New (unstable) flavors, with direct counterparts in `LinkerFlavor`.
+    // Modern (unstable) flavors, with direct counterparts in `LinkerFlavor`.
     Gnu(Cc, Lld),
     Darwin(Cc, Lld),
     WasmLld(Cc),
@@ -179,13 +179,11 @@ pub enum LinkerFlavorCli {
     Bpf,
     Ptx,
 
-    // Below: the legacy stable values.
+    // Legacy stable values
     Gcc,
     Ld,
     Lld(LldFlavor),
     Em,
-    BpfLinker,
-    PtxLinker,
 }
 
 impl LinkerFlavorCli {
@@ -199,9 +197,7 @@ impl LinkerFlavorCli {
             | LinkerFlavorCli::Msvc(Lld::Yes)
             | LinkerFlavorCli::EmCc
             | LinkerFlavorCli::Bpf
-            | LinkerFlavorCli::Ptx
-            | LinkerFlavorCli::BpfLinker
-            | LinkerFlavorCli::PtxLinker => true,
+            | LinkerFlavorCli::Ptx => true,
             LinkerFlavorCli::Gcc
             | LinkerFlavorCli::Ld
             | LinkerFlavorCli::Lld(..)
@@ -279,8 +275,6 @@ impl LinkerFlavor {
             LinkerFlavorCli::Lld(LldFlavor::Wasm) => LinkerFlavor::WasmLld(Cc::No),
             LinkerFlavorCli::Lld(LldFlavor::Link) => LinkerFlavor::Msvc(Lld::Yes),
             LinkerFlavorCli::Em => LinkerFlavor::EmCc,
-            LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf,
-            LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx,
         }
     }
 
@@ -299,8 +293,8 @@ impl LinkerFlavor {
             LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Link),
             LinkerFlavor::Msvc(..) => LinkerFlavorCli::Msvc(Lld::No),
             LinkerFlavor::EmCc => LinkerFlavorCli::Em,
-            LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker,
-            LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker,
+            LinkerFlavor::Bpf => LinkerFlavorCli::Bpf,
+            LinkerFlavor::Ptx => LinkerFlavorCli::Ptx,
         }
     }
 
@@ -320,7 +314,6 @@ impl LinkerFlavor {
             LinkerFlavorCli::Ld => (Some(Cc::No), Some(Lld::No)),
             LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)),
             LinkerFlavorCli::Em => (Some(Cc::Yes), Some(Lld::Yes)),
-            LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker => (None, None),
         }
     }
 
@@ -511,7 +504,7 @@ linker_flavor_cli_impls! {
     (LinkerFlavorCli::Bpf) "bpf"
     (LinkerFlavorCli::Ptx) "ptx"
 
-    // Below: legacy stable values
+    // Legacy stable flavors
     (LinkerFlavorCli::Gcc) "gcc"
     (LinkerFlavorCli::Ld) "ld"
     (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld"
@@ -519,8 +512,6 @@ linker_flavor_cli_impls! {
     (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link"
     (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld"
     (LinkerFlavorCli::Em) "em"
-    (LinkerFlavorCli::BpfLinker) "bpf-linker"
-    (LinkerFlavorCli::PtxLinker) "ptx-linker"
 }
 
 impl ToJson for LinkerFlavorCli {
@@ -529,6 +520,80 @@ impl ToJson for LinkerFlavorCli {
     }
 }
 
+bitflags::bitflags! {
+    #[derive(Default)]
+    /// The `-C link-self-contained` components that can individually be enabled or disabled.
+    pub struct LinkSelfContainedComponents: u8 {
+        /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets)
+        const CRT_OBJECTS = 1 << 0;
+        /// libc static library (e.g. on `musl`, `wasi` targets)
+        const LIBC        = 1 << 1;
+        /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
+        const UNWIND      = 1 << 2;
+        /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
+        const LINKER      = 1 << 3;
+        /// Sanitizer runtime libraries
+        const SANITIZERS  = 1 << 4;
+        /// Other MinGW libs and Windows import libs
+        const MINGW       = 1 << 5;
+    }
+}
+
+impl LinkSelfContainedComponents {
+    /// Parses a single `-Clink-self-contained` well-known component, not a set of flags.
+    pub fn from_str(s: &str) -> Option<LinkSelfContainedComponents> {
+        Some(match s {
+            "crto" => LinkSelfContainedComponents::CRT_OBJECTS,
+            "libc" => LinkSelfContainedComponents::LIBC,
+            "unwind" => LinkSelfContainedComponents::UNWIND,
+            "linker" => LinkSelfContainedComponents::LINKER,
+            "sanitizers" => LinkSelfContainedComponents::SANITIZERS,
+            "mingw" => LinkSelfContainedComponents::MINGW,
+            _ => return None,
+        })
+    }
+
+    /// Return the component's name.
+    ///
+    /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
+    pub fn as_str(self) -> Option<&'static str> {
+        Some(match self {
+            LinkSelfContainedComponents::CRT_OBJECTS => "crto",
+            LinkSelfContainedComponents::LIBC => "libc",
+            LinkSelfContainedComponents::UNWIND => "unwind",
+            LinkSelfContainedComponents::LINKER => "linker",
+            LinkSelfContainedComponents::SANITIZERS => "sanitizers",
+            LinkSelfContainedComponents::MINGW => "mingw",
+            _ => return None,
+        })
+    }
+
+    /// Returns an array of all the components.
+    fn all_components() -> [LinkSelfContainedComponents; 6] {
+        [
+            LinkSelfContainedComponents::CRT_OBJECTS,
+            LinkSelfContainedComponents::LIBC,
+            LinkSelfContainedComponents::UNWIND,
+            LinkSelfContainedComponents::LINKER,
+            LinkSelfContainedComponents::SANITIZERS,
+            LinkSelfContainedComponents::MINGW,
+        ]
+    }
+}
+
+impl IntoIterator for LinkSelfContainedComponents {
+    type Item = LinkSelfContainedComponents;
+    type IntoIter = std::vec::IntoIter<LinkSelfContainedComponents>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        LinkSelfContainedComponents::all_components()
+            .into_iter()
+            .filter(|&s| self.contains(s))
+            .collect::<Vec<_>>()
+            .into_iter()
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
 pub enum PanicStrategy {
     Unwind,
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 56d37d58de7..5ba29f87855 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,6 +11,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 066129d8e47..066129d8e47 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 77a3b5e1284..d45fe102805 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -32,14 +32,11 @@ mod assembly;
 mod canonicalize;
 mod eval_ctxt;
 mod fulfill;
-mod inherent_projection;
 pub mod inspect;
 mod normalize;
-mod opaques;
 mod project_goals;
 mod search_graph;
 mod trait_goals;
-mod weak_types;
 
 pub use eval_ctxt::{
     EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
diff --git a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
index 28fe59b7f6a..28fe59b7f6a 100644
--- a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
index 339a3e73846..2c000293f26 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
@@ -18,6 +18,10 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
 use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
 
+mod inherent_projection;
+mod opaques;
+mod weak_types;
+
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn compute_projection_goal(
diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
index f08adc0208b..ebd129f32b9 100644
--- a/compiler/rustc_trait_selection/src/solve/opaques.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
@@ -7,7 +7,7 @@ use rustc_middle::traits::Reveal;
 use rustc_middle::ty;
 use rustc_middle::ty::util::NotUniqueParam;
 
-use super::{EvalCtxt, SolverMode};
+use crate::solve::{EvalCtxt, SolverMode};
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn normalize_opaque_type(
diff --git a/compiler/rustc_trait_selection/src/solve/weak_types.rs b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
index 54de32cf618..54de32cf618 100644
--- a/compiler/rustc_trait_selection/src/solve/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 33513f6bd43..33513f6bd43 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
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 9d7933e23a8..a5ccf62608e 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
@@ -157,10 +157,18 @@ where
         }
 
         let mut region_constraints = QueryRegionConstraints::default();
-        let (output, error_info, mut obligations, _) =
-            Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
-                infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}"))
-            })?;
+        let (output, error_info, mut obligations) =
+            Q::fully_perform_into(self, infcx, &mut region_constraints)
+                .map_err(|_| {
+                    infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}"))
+                })
+                .and_then(|(output, error_info, obligations, certainty)| match certainty {
+                    Certainty::Proven => Ok((output, error_info, obligations)),
+                    Certainty::Ambiguous => Err(infcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(span, format!("ambiguity performing {self:?}"))),
+                })?;
 
         // Typically, instantiating NLL query results does not
         // create obligations. However, in some cases there
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 147b600f7ba..1a9de150041 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,6 +5,9 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(assert_matches)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs
index f36f4ec8697..f1037fe0baf 100644
--- a/compiler/rustc_type_ir/src/structural_impls.rs
+++ b/compiler/rustc_type_ir/src/structural_impls.rs
@@ -153,6 +153,12 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
     }
 }
 
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
+
 impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
     fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|x| x.try_fold_with(folder))
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 104985493ef..f371f46204f 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -22,7 +22,8 @@ use std::fmt;
 use std::fmt::Debug;
 
 use self::ty::{
-    GenericPredicates, Generics, ImplDef, ImplTrait, Span, TraitDecl, TraitDef, Ty, TyKind,
+    GenericPredicates, Generics, ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty,
+    TyKind,
 };
 
 #[macro_use]
@@ -41,7 +42,7 @@ pub type CrateNum = usize;
 
 /// A unique identification number for each item accessible for the current compilation unit.
 #[derive(Clone, Copy, PartialEq, Eq)]
-pub struct DefId(pub usize);
+pub struct DefId(usize);
 
 impl Debug for DefId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -52,9 +53,28 @@ impl Debug for DefId {
     }
 }
 
+impl IndexedVal for DefId {
+    fn to_val(index: usize) -> Self {
+        DefId(index)
+    }
+
+    fn to_index(&self) -> usize {
+        self.0
+    }
+}
+
 /// A unique identification number for each provenance
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct AllocId(pub usize);
+pub struct AllocId(usize);
+
+impl IndexedVal for AllocId {
+    fn to_val(index: usize) -> Self {
+        AllocId(index)
+    }
+    fn to_index(&self) -> usize {
+        self.0
+    }
+}
 
 /// A list of crate items.
 pub type CrateItems = Vec<CrateItem>;
@@ -125,9 +145,9 @@ pub fn local_crate() -> Crate {
     with(|cx| cx.local_crate())
 }
 
-/// Try to find a crate with the given name.
-pub fn find_crate(name: &str) -> Option<Crate> {
-    with(|cx| cx.find_crate(name))
+/// Try to find a crate or crates if multiple crates exist from given name.
+pub fn find_crates(name: &str) -> Vec<Crate> {
+    with(|cx| cx.find_crates(name))
 }
 
 /// Try to find a crate with the given name.
@@ -174,7 +194,7 @@ pub trait Context {
     fn external_crates(&self) -> Vec<Crate>;
 
     /// Find a crate with the given name.
-    fn find_crate(&self, name: &str) -> Option<Crate>;
+    fn find_crates(&self, name: &str) -> Vec<Crate>;
 
     /// Prints the name of given `DefId`
     fn name_of_def_id(&self, def_id: DefId) -> String;
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 6029e3c11ad..691af15da8c 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -75,7 +75,7 @@ pub struct Placeholder<T> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq)]
-pub struct Span(pub usize);
+pub struct Span(usize);
 
 impl Debug for Span {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@@ -86,6 +86,15 @@ impl Debug for Span {
     }
 }
 
+impl IndexedVal for Span {
+    fn to_val(index: usize) -> Self {
+        Span(index)
+    }
+    fn to_index(&self) -> usize {
+        self.0
+    }
+}
+
 #[derive(Clone, Debug)]
 pub enum TyKind {
     RigidTy(RigidTy),
@@ -565,3 +574,9 @@ pub enum ImplPolarity {
     Negative,
     Reservation,
 }
+
+pub trait IndexedVal {
+    fn to_val(index: usize) -> Self;
+
+    fn to_index(&self) -> usize;
+}
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 5481b327d69..4bdd9639557 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -669,7 +669,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// map.insert(1, "a");
     /// ```
     #[unstable(feature = "btreemap_alloc", issue = "32838")]
-    pub fn new_in(alloc: A) -> BTreeMap<K, V, A> {
+    pub const fn new_in(alloc: A) -> BTreeMap<K, V, A> {
         BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc), _marker: PhantomData }
     }
 }
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 9da230915b8..0e03551286e 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -358,7 +358,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// let mut set: BTreeSet<i32> = BTreeSet::new_in(Global);
     /// ```
     #[unstable(feature = "btreemap_alloc", issue = "32838")]
-    pub fn new_in(alloc: A) -> BTreeSet<T, A> {
+    pub const fn new_in(alloc: A) -> BTreeSet<T, A> {
         BTreeSet { map: BTreeMap::new_in(alloc) }
     }
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index cd3648214a4..d47f9de941c 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -78,6 +78,8 @@
     not(no_sync),
     target_has_atomic = "ptr"
 ))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![no_std]
 #![needs_allocator]
 // Lints:
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index e42bed7d264..4d6968157de 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -714,6 +714,156 @@ impl String {
             .collect()
     }
 
+    /// Decode a UTF-16LE–encoded vector `v` into a `String`, returning [`Err`]
+    /// if `v` contains any invalid data.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(str_from_utf16_endian)]
+    /// // 𝄞music
+    /// let v = &[0x34, 0xD8, 0x1E, 0xDD, 0x6d, 0x00, 0x75, 0x00,
+    ///           0x73, 0x00, 0x69, 0x00, 0x63, 0x00];
+    /// assert_eq!(String::from("𝄞music"),
+    ///            String::from_utf16le(v).unwrap());
+    ///
+    /// // 𝄞mu<invalid>ic
+    /// let v = &[0x34, 0xD8, 0x1E, 0xDD, 0x6d, 0x00, 0x75, 0x00,
+    ///           0x00, 0xD8, 0x69, 0x00, 0x63, 0x00];
+    /// assert!(String::from_utf16le(v).is_err());
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "str_from_utf16_endian", issue = "116258")]
+    pub fn from_utf16le(v: &[u8]) -> Result<String, FromUtf16Error> {
+        if v.len() % 2 != 0 {
+            return Err(FromUtf16Error(()));
+        }
+        match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) {
+            (true, ([], v, [])) => Self::from_utf16(v),
+            _ => char::decode_utf16(v.array_chunks::<2>().copied().map(u16::from_le_bytes))
+                .collect::<Result<_, _>>()
+                .map_err(|_| FromUtf16Error(())),
+        }
+    }
+
+    /// Decode a UTF-16LE–encoded slice `v` into a `String`, replacing
+    /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD].
+    ///
+    /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`],
+    /// `from_utf16le_lossy` returns a `String` since the UTF-16 to UTF-8
+    /// conversion requires a memory allocation.
+    ///
+    /// [`from_utf8_lossy`]: String::from_utf8_lossy
+    /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow"
+    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(str_from_utf16_endian)]
+    /// // 𝄞mus<invalid>ic<invalid>
+    /// let v = &[0x34, 0xD8, 0x1E, 0xDD, 0x6d, 0x00, 0x75, 0x00,
+    ///           0x73, 0x00, 0x1E, 0xDD, 0x69, 0x00, 0x63, 0x00,
+    ///           0x34, 0xD8];
+    ///
+    /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"),
+    ///            String::from_utf16le_lossy(v));
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "str_from_utf16_endian", issue = "116258")]
+    pub fn from_utf16le_lossy(v: &[u8]) -> String {
+        match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) {
+            (true, ([], v, [])) => Self::from_utf16_lossy(v),
+            (true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}",
+            _ => {
+                let mut iter = v.array_chunks::<2>();
+                let string = char::decode_utf16(iter.by_ref().copied().map(u16::from_le_bytes))
+                    .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
+                    .collect();
+                if iter.remainder().is_empty() { string } else { string + "\u{FFFD}" }
+            }
+        }
+    }
+
+    /// Decode a UTF-16BE–encoded vector `v` into a `String`, returning [`Err`]
+    /// if `v` contains any invalid data.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(str_from_utf16_endian)]
+    /// // 𝄞music
+    /// let v = &[0xD8, 0x34, 0xDD, 0x1E, 0x00, 0x6d, 0x00, 0x75,
+    ///           0x00, 0x73, 0x00, 0x69, 0x00, 0x63];
+    /// assert_eq!(String::from("𝄞music"),
+    ///            String::from_utf16be(v).unwrap());
+    ///
+    /// // 𝄞mu<invalid>ic
+    /// let v = &[0xD8, 0x34, 0xDD, 0x1E, 0x00, 0x6d, 0x00, 0x75,
+    ///           0xD8, 0x00, 0x00, 0x69, 0x00, 0x63];
+    /// assert!(String::from_utf16be(v).is_err());
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "str_from_utf16_endian", issue = "116258")]
+    pub fn from_utf16be(v: &[u8]) -> Result<String, FromUtf16Error> {
+        if v.len() % 2 != 0 {
+            return Err(FromUtf16Error(()));
+        }
+        match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) {
+            (true, ([], v, [])) => Self::from_utf16(v),
+            _ => char::decode_utf16(v.array_chunks::<2>().copied().map(u16::from_be_bytes))
+                .collect::<Result<_, _>>()
+                .map_err(|_| FromUtf16Error(())),
+        }
+    }
+
+    /// Decode a UTF-16BE–encoded slice `v` into a `String`, replacing
+    /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD].
+    ///
+    /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`],
+    /// `from_utf16le_lossy` returns a `String` since the UTF-16 to UTF-8
+    /// conversion requires a memory allocation.
+    ///
+    /// [`from_utf8_lossy`]: String::from_utf8_lossy
+    /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow"
+    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(str_from_utf16_endian)]
+    /// // 𝄞mus<invalid>ic<invalid>
+    /// let v = &[0xD8, 0x34, 0xDD, 0x1E, 0x00, 0x6d, 0x00, 0x75,
+    ///           0x00, 0x73, 0xDD, 0x1E, 0x00, 0x69, 0x00, 0x63,
+    ///           0xD8, 0x34];
+    ///
+    /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"),
+    ///            String::from_utf16be_lossy(v));
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "str_from_utf16_endian", issue = "116258")]
+    pub fn from_utf16be_lossy(v: &[u8]) -> String {
+        match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) {
+            (true, ([], v, [])) => Self::from_utf16_lossy(v),
+            (true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}",
+            _ => {
+                let mut iter = v.array_chunks::<2>();
+                let string = char::decode_utf16(iter.by_ref().copied().map(u16::from_be_bytes))
+                    .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
+                    .collect();
+                if iter.remainder().is_empty() { string } else { string + "\u{FFFD}" }
+            }
+        }
+    }
+
     /// Decomposes a `String` into its raw components.
     ///
     /// Returns the raw pointer to the underlying data, the length of
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 7fa7e83a744..906421327cb 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -68,6 +68,7 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![doc(cfg_hide(
     not(test),
     any(not(feature = "miri-test-libstd"), test, doctest),
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index a19fcf93c4d..f58c91a2484 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2482,6 +2482,62 @@ impl<T> [T] {
         RSplitNMut::new(self.rsplit_mut(pred), n)
     }
 
+    /// Splits the slice on the first element that matches the specified
+    /// predicate.
+    ///
+    /// If any matching elements are resent in the slice, returns the prefix
+    /// before the match and suffix after. The matching element itself is not
+    /// included. If no elements match, returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_split_once)]
+    /// let s = [1, 2, 3, 2, 4];
+    /// assert_eq!(s.split_once(|&x| x == 2), Some((
+    ///     &[1][..],
+    ///     &[3, 2, 4][..]
+    /// )));
+    /// assert_eq!(s.split_once(|&x| x == 0), None);
+    /// ```
+    #[unstable(feature = "slice_split_once", reason = "newly added", issue = "112811")]
+    #[inline]
+    pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
+    where
+        F: FnMut(&T) -> bool,
+    {
+        let index = self.iter().position(pred)?;
+        Some((&self[..index], &self[index + 1..]))
+    }
+
+    /// Splits the slice on the last element that matches the specified
+    /// predicate.
+    ///
+    /// If any matching elements are resent in the slice, returns the prefix
+    /// before the match and suffix after. The matching element itself is not
+    /// included. If no elements match, returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_split_once)]
+    /// let s = [1, 2, 3, 2, 4];
+    /// assert_eq!(s.rsplit_once(|&x| x == 2), Some((
+    ///     &[1, 2, 3][..],
+    ///     &[4][..]
+    /// )));
+    /// assert_eq!(s.rsplit_once(|&x| x == 0), None);
+    /// ```
+    #[unstable(feature = "slice_split_once", reason = "newly added", issue = "112811")]
+    #[inline]
+    pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
+    where
+        F: FnMut(&T) -> bool,
+    {
+        let index = self.iter().rposition(pred)?;
+        Some((&self[..index], &self[index + 1..]))
+    }
+
     /// Returns `true` if the slice contains an element with the given value.
     ///
     /// This operation is *O*(*n*).
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index cd16810c4dd..c30f01b3c06 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -1360,7 +1360,7 @@ impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> {
 }
 
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
+impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator
     for SplitInclusive<'a, P>
 {
     #[inline]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index e4003a208bc..1a01efa5ba9 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -49,6 +49,7 @@
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(slice_from_ptr_range)]
+#![feature(slice_split_once)]
 #![feature(split_as_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_write_slice)]
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 865e702b5c2..666452ead3f 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -2476,6 +2476,26 @@ fn slice_rsplit_array_mut_out_of_bounds() {
     let _ = v.rsplit_array_mut::<7>();
 }
 
+#[test]
+fn slice_split_once() {
+    let v = &[1, 2, 3, 2, 4][..];
+
+    assert_eq!(v.split_once(|&x| x == 2), Some((&[1][..], &[3, 2, 4][..])));
+    assert_eq!(v.split_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..])));
+    assert_eq!(v.split_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..])));
+    assert_eq!(v.split_once(|&x| x == 0), None);
+}
+
+#[test]
+fn slice_rsplit_once() {
+    let v = &[1, 2, 3, 2, 4][..];
+
+    assert_eq!(v.rsplit_once(|&x| x == 2), Some((&[1, 2, 3][..], &[4][..])));
+    assert_eq!(v.rsplit_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..])));
+    assert_eq!(v.rsplit_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..])));
+    assert_eq!(v.rsplit_once(|&x| x == 0), None);
+}
+
 macro_rules! take_tests {
     (slice: &[], $($tts:tt)*) => {
         take_tests!(ty: &[()], slice: &[], $($tts)*);
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 0a70c488aec..991fdb1256d 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -17,6 +17,8 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 // This library is copied into rust-analyzer to allow loading rustc compiled proc macros.
 // Please avoid unstable features where possible to minimize the amount of changes necessary
 // to make it compile with rust-analyzer on stable.
diff --git a/library/std/build.rs b/library/std/build.rs
index 164bca7c436..49354d5a58c 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -42,6 +42,7 @@ fn main() {
         || target.contains("solid")
         || target.contains("nintendo-3ds")
         || target.contains("vita")
+        || target.contains("aix")
         || target.contains("nto")
         || target.contains("xous")
         || target.contains("hurd")
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 6d85b26af5f..6a87f6e5f2d 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -144,7 +144,7 @@ impl<T> HashSet<T, RandomState> {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize) -> HashSet<T, RandomState> {
-        HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, Default::default()) }
+        HashSet::with_capacity_and_hasher(capacity, Default::default())
     }
 }
 
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index c93bf020252..e6431abcf82 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -513,8 +513,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
         match this.read(buf) {
             Ok(0) => break,
             Ok(n) => {
-                let tmp = buf;
-                buf = &mut tmp[n..];
+                buf = &mut buf[n..];
             }
             Err(ref e) if e.is_interrupted() => {}
             Err(e) => return Err(e),
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 02f4d5bc7ae..aaf20875129 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -227,6 +227,7 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![doc(cfg_hide(
     not(test),
     not(any(test, bootstrap)),
diff --git a/library/std/src/os/aix/fs.rs b/library/std/src/os/aix/fs.rs
new file mode 100644
index 00000000000..ac9dd45f054
--- /dev/null
+++ b/library/std/src/os/aix/fs.rs
@@ -0,0 +1,348 @@
+//! AIX specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Returns the device ID on which this file resides.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_dev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    /// Returns the inode number.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ino());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    /// Returns the file type and mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mode());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+    /// Returns the number of hard links to file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_nlink());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    /// Returns the user ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_uid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    /// Returns the group ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_gid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    /// Returns the device ID that this file represents. Only relevant for special file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_rdev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+    ///
+    /// The size of a symbolic link is the length of the pathname it contains,
+    /// without a terminating null byte.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_size());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    /// Returns the last access time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+    ///
+    /// [`st_atime`]: Self::st_atime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    /// Returns the last modification time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+    ///
+    /// [`st_mtime`]: Self::st_mtime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    /// Returns the last status change time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+    ///
+    /// [`st_ctime`]: Self::st_ctime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    /// Returns the "preferred" block size for efficient filesystem I/O.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blksize());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    /// Returns the number of blocks allocated to the file, 512-byte units.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::aix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blocks());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime.tv_sec as i64
+    }
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atime.tv_nsec as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime.tv_sec as i64
+    }
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime.tv_nsec as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime.tv_sec as i64
+    }
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime.tv_nsec as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/library/std/src/os/aix/mod.rs b/library/std/src/os/aix/mod.rs
new file mode 100644
index 00000000000..7f86a3c77f2
--- /dev/null
+++ b/library/std/src/os/aix/mod.rs
@@ -0,0 +1,6 @@
+//! AIX specific definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/aix/raw.rs b/library/std/src/os/aix/raw.rs
new file mode 100644
index 00000000000..b4c8dc72cfe
--- /dev/null
+++ b/library/std/src/os/aix/raw.rs
@@ -0,0 +1,9 @@
+//! AIX specific raw type definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use libc::pthread_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, stat, time_t};
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 11ad21515fd..6e11b92b618 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -97,6 +97,8 @@ pub mod wasi;
 pub mod windows;
 
 // Others.
+#[cfg(target_os = "aix")]
+pub mod aix;
 #[cfg(target_os = "android")]
 pub mod android;
 #[cfg(target_os = "dragonfly")]
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 3724e90afbd..5ba8719e6ff 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -37,6 +37,8 @@ use crate::os::linux as platform;
 
 #[cfg(not(doc))]
 mod platform {
+    #[cfg(target_os = "aix")]
+    pub use crate::os::aix::*;
     #[cfg(target_os = "android")]
     pub use crate::os::android::*;
     #[cfg(target_os = "dragonfly")]
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index 19334e2aff2..2da17fabcd6 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -70,6 +70,7 @@ impl DoubleEndedIterator for Args {
     target_os = "redox",
     target_os = "vxworks",
     target_os = "horizon",
+    target_os = "aix",
     target_os = "nto",
     target_os = "hurd",
 ))]
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index c6d8578a629..3bb492fa98b 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -261,3 +261,14 @@ pub mod os {
     pub const EXE_SUFFIX: &str = "";
     pub const EXE_EXTENSION: &str = "";
 }
+
+#[cfg(target_os = "aix")]
+pub mod os {
+    pub const FAMILY: &str = "unix";
+    pub const OS: &str = "aix";
+    pub const DLL_PREFIX: &str = "lib";
+    pub const DLL_SUFFIX: &str = ".a";
+    pub const DLL_EXTENSION: &str = "a";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 5ed2bdd7fe3..e1c58f2ba3c 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -54,6 +54,7 @@ use libc::fstatat64;
     target_os = "fuchsia",
     target_os = "redox",
     target_os = "illumos",
+    target_os = "aix",
     target_os = "nto",
     target_os = "vita",
 ))]
@@ -71,6 +72,7 @@ use libc::readdir64_r;
     target_os = "l4re",
     target_os = "fuchsia",
     target_os = "redox",
+    target_os = "aix",
     target_os = "nto",
     target_os = "vita",
     target_os = "hurd",
@@ -288,6 +290,7 @@ unsafe impl Sync for Dir {}
     target_os = "illumos",
     target_os = "fuchsia",
     target_os = "redox",
+    target_os = "aix",
     target_os = "nto",
     target_os = "vita",
     target_os = "hurd",
@@ -311,6 +314,7 @@ pub struct DirEntry {
     target_os = "illumos",
     target_os = "fuchsia",
     target_os = "redox",
+    target_os = "aix",
     target_os = "nto",
     target_os = "vita",
     target_os = "hurd",
@@ -320,8 +324,9 @@ struct dirent64_min {
     #[cfg(not(any(
         target_os = "solaris",
         target_os = "illumos",
+        target_os = "aix",
         target_os = "nto",
-        target_os = "vita"
+        target_os = "vita",
     )))]
     d_type: u8,
 }
@@ -333,6 +338,7 @@ struct dirent64_min {
     target_os = "illumos",
     target_os = "fuchsia",
     target_os = "redox",
+    target_os = "aix",
     target_os = "nto",
     target_os = "vita",
     target_os = "hurd",
@@ -464,7 +470,22 @@ impl FileAttr {
     }
 }
 
-#[cfg(not(any(target_os = "netbsd", target_os = "nto")))]
+#[cfg(target_os = "aix")]
+impl FileAttr {
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64))
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64))
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64))
+    }
+}
+
+#[cfg(not(any(target_os = "netbsd", target_os = "nto", target_os = "aix")))]
 impl FileAttr {
     #[cfg(not(any(
         target_os = "vxworks",
@@ -671,6 +692,7 @@ impl Iterator for ReadDir {
         target_os = "fuchsia",
         target_os = "redox",
         target_os = "illumos",
+        target_os = "aix",
         target_os = "nto",
         target_os = "vita",
         target_os = "hurd",
@@ -748,6 +770,7 @@ impl Iterator for ReadDir {
                     #[cfg(not(any(
                         target_os = "solaris",
                         target_os = "illumos",
+                        target_os = "aix",
                         target_os = "nto",
                     )))]
                     d_type: *offset_ptr!(entry_ptr, d_type) as u8,
@@ -772,6 +795,7 @@ impl Iterator for ReadDir {
         target_os = "fuchsia",
         target_os = "redox",
         target_os = "illumos",
+        target_os = "aix",
         target_os = "nto",
         target_os = "vita",
         target_os = "hurd",
@@ -874,6 +898,7 @@ impl DirEntry {
         target_os = "illumos",
         target_os = "haiku",
         target_os = "vxworks",
+        target_os = "aix",
         target_os = "nto",
         target_os = "vita",
     ))]
@@ -886,6 +911,7 @@ impl DirEntry {
         target_os = "illumos",
         target_os = "haiku",
         target_os = "vxworks",
+        target_os = "aix",
         target_os = "nto",
         target_os = "vita",
     )))]
@@ -920,6 +946,7 @@ impl DirEntry {
         target_os = "espidf",
         target_os = "horizon",
         target_os = "vita",
+        target_os = "aix",
         target_os = "nto",
         target_os = "hurd",
     ))]
@@ -977,6 +1004,7 @@ impl DirEntry {
         target_os = "illumos",
         target_os = "fuchsia",
         target_os = "redox",
+        target_os = "aix",
         target_os = "nto",
         target_os = "vita",
         target_os = "hurd",
@@ -991,6 +1019,7 @@ impl DirEntry {
         target_os = "illumos",
         target_os = "fuchsia",
         target_os = "redox",
+        target_os = "aix",
         target_os = "nto",
         target_os = "vita",
         target_os = "hurd",
@@ -2026,6 +2055,7 @@ mod remove_dir_impl {
         target_os = "illumos",
         target_os = "haiku",
         target_os = "vxworks",
+        target_os = "aix",
     ))]
     fn is_dir(_ent: &DirEntry) -> Option<bool> {
         None
@@ -2036,6 +2066,7 @@ mod remove_dir_impl {
         target_os = "illumos",
         target_os = "haiku",
         target_os = "vxworks",
+        target_os = "aix",
     )))]
     fn is_dir(ent: &DirEntry) -> Option<bool> {
         match ent.entry.d_type {
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 3edafde71e9..01d8217342c 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -278,6 +278,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ENETUNREACH => NetworkUnreachable,
         libc::ENOTCONN => NotConnected,
         libc::ENOTDIR => NotADirectory,
+        #[cfg(not(target_os = "aix"))]
         libc::ENOTEMPTY => DirectoryNotEmpty,
         libc::EPIPE => BrokenPipe,
         libc::EROFS => ReadOnlyFilesystem,
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 01ff375d215..dc3c037c0cb 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -74,6 +74,7 @@ extern "C" {
         link_name = "__error"
     )]
     #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
+    #[cfg_attr(target_os = "aix", link_name = "_Errno")]
     fn errno_location() -> *mut c_int;
 }
 
@@ -254,6 +255,41 @@ impl StdError for JoinPathsError {
     }
 }
 
+#[cfg(target_os = "aix")]
+pub fn current_exe() -> io::Result<PathBuf> {
+    use crate::io::ErrorKind;
+
+    #[cfg(test)]
+    use realstd::env;
+
+    #[cfg(not(test))]
+    use crate::env;
+
+    let exe_path = env::args().next().ok_or(io::const_io_error!(
+        ErrorKind::NotFound,
+        "an executable path was not found because no arguments were provided through argv"
+    ))?;
+    let path = PathBuf::from(exe_path);
+    if path.is_absolute() {
+        return path.canonicalize();
+    }
+    // Search PWD to infer current_exe.
+    if let Some(pstr) = path.to_str() && pstr.contains("/") {
+        return getcwd().map(|cwd| cwd.join(path))?.canonicalize();
+    }
+    // Search PATH to infer current_exe.
+    if let Some(p) = getenv(OsStr::from_bytes("PATH".as_bytes())) {
+        for search_path in split_paths(&p) {
+            let pb = search_path.join(&path);
+            if pb.is_file() && let Ok(metadata) = crate::fs::metadata(&pb) &&
+               metadata.permissions().mode() & 0o111 != 0 {
+                return pb.canonicalize();
+            }
+        }
+    }
+    Err(io::const_io_error!(ErrorKind::NotFound, "an executable path was not found"))
+}
+
 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     unsafe {
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 311ed95022f..e667f34aece 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -218,6 +218,7 @@ impl Thread {
         target_os = "redox",
         target_os = "vxworks",
         target_os = "hurd",
+        target_os = "aix",
     ))]
     pub fn set_name(_name: &CStr) {
         // Newlib, Emscripten, and VxWorks have no way to set a thread name.
@@ -317,6 +318,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
             target_os = "macos",
             target_os = "solaris",
             target_os = "illumos",
+            target_os = "aix",
         ))] {
             #[allow(unused_assignments)]
             #[allow(unused_mut)]
diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs
index 4a732a2cabd..a0117e1d165 100644
--- a/library/std/src/sys/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/unix/thread_local_dtor.rs
@@ -102,7 +102,12 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     }
 }
 
-#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))]
+#[cfg(any(
+    target_os = "vxworks",
+    target_os = "horizon",
+    target_os = "emscripten",
+    target_os = "aix"
+))]
 #[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::sys_common::thread_local_dtor::register_dtor_fallback;
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 413f0fba342..bddf75dffbb 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -16,6 +16,8 @@
 
 #![unstable(feature = "test", issue = "50297")]
 #![doc(test(attr(deny(warnings))))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(internal_output_capture)]
 #![feature(staged_api)]
 #![feature(process_exitcode_internals)]
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index df4f286a526..94a91dd357c 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -145,6 +145,10 @@ extern "C" {}
 #[link(name = "gcc_s")]
 extern "C" {}
 
+#[cfg(target_os = "aix")]
+#[link(name = "unwind")]
+extern "C" {}
+
 #[cfg(target_os = "nto")]
 #[link(name = "gcc_s")]
 extern "C" {}
diff --git a/src/bootstrap/bin/_helper.rs b/src/bootstrap/bin/_helper.rs
index 09aa471dba4..46c574c5bf4 100644
--- a/src/bootstrap/bin/_helper.rs
+++ b/src/bootstrap/bin/_helper.rs
@@ -14,6 +14,7 @@ fn parse_rustc_verbose() -> usize {
 /// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`.
 ///
 /// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
+#[allow(unused)]
 fn parse_rustc_stage() -> String {
     std::env::var("RUSTC_STAGE").unwrap_or_else(|_| {
         // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 20cd63b966b..b7fd2aa9637 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -27,7 +27,6 @@ fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
     let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str());
 
-    let stage = parse_rustc_stage();
     let verbose = parse_rustc_verbose();
 
     // Detect whether or not we're a build script depending on whether --target
@@ -108,36 +107,13 @@ fn main() {
             cmd.arg("-Ztls-model=initial-exec");
         }
     } else {
-        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
-        // here, but rather Cargo should know what flags to pass rustc itself.
-
-        // Override linker if necessary.
-        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
-            cmd.arg(format!("-Clinker={host_linker}"));
-        }
-        if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() {
-            cmd.arg("-Clink-args=-fuse-ld=lld");
-        }
-
-        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
-            if s == "true" {
-                cmd.arg("-C").arg("target-feature=+crt-static");
+        // Find any host flags that were passed by bootstrap.
+        // The flags are stored in a RUSTC_HOST_FLAGS variable, separated by spaces.
+        if let Ok(flags) = std::env::var("RUSTC_HOST_FLAGS") {
+            for flag in flags.split(' ') {
+                cmd.arg(flag);
             }
-            if s == "false" {
-                cmd.arg("-C").arg("target-feature=-crt-static");
-            }
-        }
-
-        // Cargo doesn't pass RUSTFLAGS to proc_macros:
-        // https://github.com/rust-lang/cargo/issues/4423
-        // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
-        // We also declare that the flag is expected, which we need to do to not
-        // get warnings about it being unexpected.
-        if stage == "0" {
-            cmd.arg("--cfg=bootstrap");
         }
-        cmd.arg("-Zunstable-options");
-        cmd.arg("--check-cfg=values(bootstrap)");
     }
 
     if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 4af97b2f466..1a1125a107f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -954,6 +954,13 @@ class RustBuild(object):
         if deny_warnings:
             env["RUSTFLAGS"] += " -Dwarnings"
 
+        # Add RUSTFLAGS_BOOTSTRAP to RUSTFLAGS for bootstrap compilation.
+        # Note that RUSTFLAGS_BOOTSTRAP should always be added to the end of
+        # RUSTFLAGS to be actually effective (e.g., if we have `-Dwarnings` in
+        # RUSTFLAGS, passing `-Awarnings` from RUSTFLAGS_BOOTSTRAP should override it).
+        if "RUSTFLAGS_BOOTSTRAP" in env:
+            env["RUSTFLAGS"] += " " + env["RUSTFLAGS_BOOTSTRAP"]
+
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
             os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 46a62eed952..c714b09ec3c 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1174,9 +1174,6 @@ impl<'a> Builder<'a> {
         if let Some(linker) = self.linker(compiler.host) {
             cmd.env("RUSTDOC_LINKER", linker);
         }
-        if self.is_fuse_ld_lld(compiler.host) {
-            cmd.env("RUSTDOC_FUSE_LD_LLD", "1");
-        }
         cmd
     }
 
@@ -1268,6 +1265,8 @@ impl<'a> Builder<'a> {
         let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
         let out_dir = self.stage_out(compiler, mode);
 
+        let mut hostflags = HostFlags::default();
+
         // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
         // so we need to explicitly clear out if they've been updated.
         for backend in self.codegen_backends(compiler) {
@@ -1439,6 +1438,20 @@ impl<'a> Builder<'a> {
             }
         }
 
+        // FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments
+        // to the host invocation here, but rather Cargo should know what flags to pass rustc
+        // itself.
+        if stage == 0 {
+            hostflags.arg("--cfg=bootstrap");
+        }
+        // Cargo doesn't pass RUSTFLAGS to proc_macros:
+        // https://github.com/rust-lang/cargo/issues/4423
+        // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
+        // We also declare that the flag is expected, which we need to do to not
+        // get warnings about it being unexpected.
+        hostflags.arg("-Zunstable-options");
+        hostflags.arg("--check-cfg=values(bootstrap)");
+
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
         // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
         // #71458.
@@ -1655,11 +1668,10 @@ impl<'a> Builder<'a> {
         }
 
         if let Some(host_linker) = self.linker(compiler.host) {
-            cargo.env("RUSTC_HOST_LINKER", host_linker);
+            hostflags.arg(format!("-Clinker={}", host_linker.display()));
         }
         if self.is_fuse_ld_lld(compiler.host) {
-            cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1");
-            cargo.env("RUSTDOC_FUSE_LD_LLD", "1");
+            hostflags.arg("-Clink-args=-fuse-ld=lld");
         }
 
         if let Some(target_linker) = self.linker(target) {
@@ -1743,7 +1755,8 @@ impl<'a> Builder<'a> {
         }
 
         if let Some(x) = self.crt_static(compiler.host) {
-            cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
+            let sign = if x { "+" } else { "-" };
+            hostflags.arg(format!("-Ctarget-feature={sign}crt-static"));
         }
 
         if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
@@ -2055,7 +2068,7 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTFLAGS", &rustc_args.join(" "));
         }
 
-        Cargo { command: cargo, rustflags, rustdocflags, allow_features }
+        Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features }
     }
 
     /// Ensure that a given step is built, returning its output. This will
@@ -2233,11 +2246,36 @@ impl Rustflags {
     }
 }
 
+/// Flags that are passed to the `rustc` shim binary.
+/// These flags will only be applied when compiling host code, i.e. when
+/// `--target` is unset.
+#[derive(Debug, Default)]
+pub struct HostFlags {
+    rustc: Vec<String>,
+}
+
+impl HostFlags {
+    const SEPARATOR: &'static str = " ";
+
+    /// Adds a host rustc flag.
+    fn arg<S: Into<String>>(&mut self, flag: S) {
+        let value = flag.into().trim().to_string();
+        assert!(!value.contains(Self::SEPARATOR));
+        self.rustc.push(value);
+    }
+
+    /// Encodes all the flags into a single string.
+    fn encode(self) -> String {
+        self.rustc.join(Self::SEPARATOR)
+    }
+}
+
 #[derive(Debug)]
 pub struct Cargo {
     command: Command,
     rustflags: Rustflags,
     rustdocflags: Rustflags,
+    hostflags: HostFlags,
     allow_features: String,
 }
 
@@ -2309,6 +2347,11 @@ impl From<Cargo> for Command {
             cargo.command.env("RUSTDOCFLAGS", rustdocflags);
         }
 
+        let encoded_hostflags = cargo.hostflags.encode();
+        if !encoded_hostflags.is_empty() {
+            cargo.command.env("RUSTC_HOST_FLAGS", encoded_hostflags);
+        }
+
         if !cargo.allow_features.is_empty() {
             cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
         }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index cf1f97c5b41..6821ded1458 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -1677,15 +1677,17 @@ impl Step for Assemble {
             let src_exe = exe("lld", target_compiler.host);
             let dst_exe = exe("rust-lld", target_compiler.host);
             builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe));
-            // for `-Z gcc-ld=lld`
-            let gcc_ld_dir = libdir_bin.join("gcc-ld");
-            t!(fs::create_dir(&gcc_ld_dir));
+            let self_contained_lld_dir = libdir_bin.join("gcc-ld");
+            t!(fs::create_dir(&self_contained_lld_dir));
             let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper {
                 compiler: build_compiler,
                 target: target_compiler.host,
             });
             for name in crate::LLD_FILE_NAMES {
-                builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host)));
+                builder.copy(
+                    &lld_wrapper_exe,
+                    &self_contained_lld_dir.join(exe(name, target_compiler.host)),
+                );
             }
         }
 
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 32da4ac29a4..05556d2f679 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -471,14 +471,15 @@ impl Step for Rustc {
                 let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
                 let rust_lld = exe("rust-lld", compiler.host);
                 builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
-                // for `-Z gcc-ld=lld`
-                let gcc_lld_src_dir = src_dir.join("gcc-ld");
-                let gcc_lld_dst_dir = dst_dir.join("gcc-ld");
-                t!(fs::create_dir(&gcc_lld_dst_dir));
+                let self_contained_lld_src_dir = src_dir.join("gcc-ld");
+                let self_contained_lld_dst_dir = dst_dir.join("gcc-ld");
+                t!(fs::create_dir(&self_contained_lld_dst_dir));
                 for name in crate::LLD_FILE_NAMES {
                     let exe_name = exe(name, compiler.host);
-                    builder
-                        .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name));
+                    builder.copy(
+                        &self_contained_lld_src_dir.join(&exe_name),
+                        &self_contained_lld_dst_dir.join(&exe_name),
+                    );
                 }
             }
 
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index 8f4ad0f4e75..3372baed999 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -29,8 +29,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   g++-arm-linux-gnueabi \
   g++-arm-linux-gnueabihf \
   g++-aarch64-linux-gnu \
-  g++-mips64-linux-gnuabi64 \
-  g++-mips64el-linux-gnuabi64 \
   gcc-arm-none-eabi \
   gcc-sparc64-linux-gnu \
   libc6-dev-sparc64-cross \
@@ -48,12 +46,6 @@ WORKDIR /build
 COPY host-x86_64/dist-various-1/install-x86_64-redox.sh /build
 RUN ./install-x86_64-redox.sh
 
-COPY host-x86_64/dist-various-1/install-mips-musl.sh /build
-RUN ./install-mips-musl.sh
-
-COPY host-x86_64/dist-various-1/install-mipsel-musl.sh /build
-RUN ./install-mipsel-musl.sh
-
 COPY host-x86_64/dist-various-1/install-aarch64-none-elf.sh /build
 RUN ./install-aarch64-none-elf.sh
 
@@ -76,32 +68,7 @@ RUN env \
     env \
     CC=arm-linux-gnueabihf-gcc CFLAGS="-march=armv7-a+fp" \
     CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv7-a+fp" \
-    bash musl.sh armv7hf && \
-    env \
-    CC=mips-openwrt-linux-gcc \
-    CXX=mips-openwrt-linux-g++ \
-    bash musl.sh mips && \
-    env \
-    CC=mipsel-openwrt-linux-gcc \
-    CXX=mipsel-openwrt-linux-g++ \
-    bash musl.sh mipsel && \
-    env \
-    CC=mips64-linux-gnuabi64-gcc \
-    CXX=mips64-linux-gnuabi64-g++ \
-    bash musl.sh mips64 && \
-    env \
-    CC=mips64el-linux-gnuabi64-gcc \
-    CXX=mips64el-linux-gnuabi64-g++ \
-    bash musl.sh mips64el && \
-    rm -rf /build/*
-
-# FIXME(mozilla/sccache#235) this shouldn't be necessary but is currently
-# necessary to disambiguate the mips compiler with the mipsel compiler. We want
-# to give these two wrapper scripts (currently identical ones) different hashes
-# to ensure that sccache understands that they're different compilers.
-RUN \
-  echo "# a" >> /usr/local/mips-linux-musl/bin/mips-openwrt-linux-musl-wrapper.sh && \
-  echo "# b" >> /usr/local/mipsel-linux-musl/bin/mipsel-openwrt-linux-musl-wrapper.sh
+    bash musl.sh armv7hf
 
 ENV RUN_MAKE_TARGETS=thumbv6m-none-eabi
 ENV RUN_MAKE_TARGETS=$RUN_MAKE_TARGETS,thumbv7m-none-eabi
@@ -110,10 +77,6 @@ ENV RUN_MAKE_TARGETS=$RUN_MAKE_TARGETS,thumbv7em-none-eabihf
 
 ENV TARGETS=asmjs-unknown-emscripten
 ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
-ENV TARGETS=$TARGETS,mips-unknown-linux-musl
-ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl
-ENV TARGETS=$TARGETS,mips64-unknown-linux-muslabi64
-ENV TARGETS=$TARGETS,mips64el-unknown-linux-muslabi64
 ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi
 ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf
 ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi
@@ -149,10 +112,6 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft
     CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \
     CFLAGS_arm_unknown_linux_musleabihf="-march=armv6 -marm -mfpu=vfp" \
     CFLAGS_armv7_unknown_linux_musleabihf="-march=armv7-a+fp" \
-    CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
-    CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
-    CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \
-    CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \
     CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \
     CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \
     CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \
@@ -177,10 +136,6 @@ ENV RUST_CONFIGURE_ARGS \
       --musl-root-arm=/musl-arm \
       --musl-root-armhf=/musl-armhf \
       --musl-root-armv7hf=/musl-armv7hf \
-      --musl-root-mips=/musl-mips \
-      --musl-root-mipsel=/musl-mipsel \
-      --musl-root-mips64=/musl-mips64 \
-      --musl-root-mips64el=/musl-mips64el \
       --disable-docs
 
 ENV SCRIPT \
diff --git a/src/ci/docker/host-x86_64/dist-various-1/install-mips-musl.sh b/src/ci/docker/host-x86_64/dist-various-1/install-mips-musl.sh
deleted file mode 100755
index abab1809346..00000000000
--- a/src/ci/docker/host-x86_64/dist-various-1/install-mips-musl.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-set -ex
-
-mkdir /usr/local/mips-linux-musl
-
-# originally from
-# https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/
-# OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2
-URL="https://ci-mirrors.rust-lang.org/rustc"
-FILE="OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2"
-curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mips-linux-musl --strip-components=2
-
-for file in /usr/local/mips-linux-musl/bin/mips-openwrt-linux-*; do
-  ln -s $file /usr/local/bin/`basename $file`
-done
diff --git a/src/ci/docker/host-x86_64/dist-various-1/install-mipsel-musl.sh b/src/ci/docker/host-x86_64/dist-various-1/install-mipsel-musl.sh
deleted file mode 100755
index 779acb2d841..00000000000
--- a/src/ci/docker/host-x86_64/dist-various-1/install-mipsel-musl.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-set -ex
-
-mkdir /usr/local/mipsel-linux-musl
-
-# Note that this originally came from:
-# https://downloads.openwrt.org/snapshots/trunk/malta/generic/
-# OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2
-URL="https://ci-mirrors.rust-lang.org/rustc"
-FILE="OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2"
-curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mipsel-linux-musl --strip-components=2
-
-for file in /usr/local/mipsel-linux-musl/bin/mipsel-openwrt-linux-*; do
-  ln -s $file /usr/local/bin/`basename $file`
-done
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
index 02b023fe75b..56ee348a337 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
@@ -4,7 +4,7 @@ set -ex
 
 source shared.sh
 
-LLVM=llvmorg-17.0.0-rc3
+LLVM=llvmorg-17.0.2
 
 mkdir llvm-project
 cd llvm-project
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index e9c155b1378..22aabda2bb3 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -264,6 +264,9 @@ else
   BASE_COMMIT=""
 fi
 
+SUMMARY_FILE=github-summary.md
+touch $objdir/${SUMMARY_FILE}
+
 docker \
   run \
   --workdir /checkout/obj \
@@ -275,6 +278,7 @@ docker \
   --env CI \
   --env GITHUB_ACTIONS \
   --env GITHUB_REF \
+  --env GITHUB_STEP_SUMMARY="/checkout/obj/${SUMMARY_FILE}" \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --env TOOLSTATE_REPO \
   --env TOOLSTATE_PUBLISH \
@@ -289,6 +293,8 @@ docker \
   rust-ci \
   $command
 
+cat $objdir/${SUMMARY_FILE} >> "${GITHUB_STEP_SUMMARY}"
+
 if [ -f /.dockerenv ]; then
   rm -rf $objdir
   docker cp checkout:/checkout/obj $objdir
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 838c72612d6..93b07350ac1 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -282,7 +282,6 @@ on:
       - try
       - try-perf
       - automation/bors/try
-      - automation/bors/try-merge
       - master
   pull_request:
     branches:
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 98f2cdac5dc..abeff7b837d 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -47,7 +47,8 @@ source "$ci_dir/shared.sh"
 
 export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
 
-if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf; then
+if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf || \
+  isCiBranch automation/bors/try; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
     HAS_METRICS=1
diff --git a/src/ci/scripts/verify-channel.sh b/src/ci/scripts/verify-channel.sh
index cd28748a44b..edeea20144b 100755
--- a/src/ci/scripts/verify-channel.sh
+++ b/src/ci/scripts/verify-channel.sh
@@ -8,7 +8,7 @@ IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
-if isCiBranch auto || isCiBranch try || isCiBranch try-perf; then
+if isCiBranch auto || isCiBranch try || isCiBranch try-perf || isCiBranch automation/bors/try; then
     echo "channel verification is only executed on PR builds"
     exit
 fi
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 5262e1c3b43a2c489df8f6717683a44c7a2260f
+Subproject 142b2ed77d33f37a9973772bd95e6144ed9dce4
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject c954202c1e1720cba5628f99543cc01188c7d6f
+Subproject 8eb3a01ab74c567b7174784892fb807f2c632d6
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject a13b7c28ed705891c681ce5417b3d1cdb12cecd
+Subproject b98af7d661e4744baab81fb8dc7a049e44a4a99
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index d72543c7e02..cfbe1e09cde 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -249,11 +249,9 @@ flavor. Valid options are:
 * `gcc`: use the `cc` executable, which is typically gcc or clang on many systems.
 * `ld`: use the `ld` executable.
 * `msvc`: use the `link.exe` executable from Microsoft Visual Studio MSVC.
-* `ptx-linker`: use
-  [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia
-  NVPTX GPGPU support.
-* `bpf-linker`: use
-  [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
+* `ptx`: use [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker)
+  for Nvidia NVPTX GPGPU support.
+* `bpf`: use [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
 * `wasm-ld`: use the [`wasm-ld`](https://lld.llvm.org/WebAssembly.html)
   executable, a port of LLVM `lld` for WebAssembly.
 * `ld64.lld`: use the LLVM `lld` executable with the [`-flavor darwin`
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index ef4eb5a1965..d25fa661c3f 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -93,10 +93,6 @@ target | notes
 `arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
 `armv7-unknown-linux-gnueabihf` | ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)
 [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)
-`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
-`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
 `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
 `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
@@ -162,10 +158,6 @@ target | std | notes
 [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * | 32-bit UEFI
 [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * |  | LoongArch64 Bare-metal (LP64D ABI)
 [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * |  | LoongArch64 Bare-metal (LP64S ABI)
-`mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL
-`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
-`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
-`mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
 [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
 `riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
 `riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
@@ -282,10 +274,22 @@ target | std | host | notes
 `i686-uwp-windows-msvc` | ? |  | [^x86_32-floats-return-ABI]
 `i686-wrs-vxworks` | ? |  | [^x86_32-floats-return-ABI]
 [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? |  | Motorola 680x0 Linux
+`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
+`mips-unknown-linux-musl` | ✓ |  | MIPS Linux with musl libc
 `mips-unknown-linux-uclibc` | ✓ |  | MIPS Linux with uClibc
 [`mips64-openwrt-linux-musl`](platform-support/mips64-openwrt-linux-musl.md) | ? |  | MIPS64 for OpenWrt Linux MUSL
+`mips64-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)
+`mips64-unknown-linux-muslabi64` | ✓ |  | MIPS64 Linux, N64 ABI, musl libc
+`mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (little endian) Linux, N64 ABI (kernel 4.4, glibc 2.23)
+`mips64el-unknown-linux-muslabi64` | ✓ |  | MIPS64 (little endian) Linux, N64 ABI, musl libc
+`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (little endian) Linux (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-musl` | ✓ |  | MIPS (little endian) Linux with musl libc
 `mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 [`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * |  | MIPS (LE) Sony PlayStation 1 (PSX)
+`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
+`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
 [`mipsisa32r6-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? |  | 32-bit MIPS Release 6 Big Endian
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 7473b09920f..199b5d69a1c 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -207,6 +207,21 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
 mod empty_mod {}
 ```
 
+### Use the Rust logo as the crate logo
+
+This is for official Rust project use only.
+
+Internal Rustdoc pages like settings.html and scrape-examples-help.html show the Rust logo.
+This logo is tracked as a static resource. The attribute `#![doc(rust_logo)]` makes this same
+built-in resource act as the main logo.
+
+```rust
+#![feature(rustdoc_internals)]
+#![allow(internal_features)]
+#![doc(rust_logo)]
+//! This crate has the Rust(tm) branding on it.
+```
+
 ## Effects of other nightly features
 
 These nightly-only features are not primarily related to Rustdoc,
diff --git a/src/doc/unstable-book/src/language-features/diagnostic-namespace.md b/src/doc/unstable-book/src/language-features/diagnostic-namespace.md
new file mode 100644
index 00000000000..7c46811a27a
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/diagnostic-namespace.md
@@ -0,0 +1,84 @@
+# `diagnostic_namespace`
+
+The tracking issue for this feature is: [#111996]
+
+[#111996]: https://github.com/rust-lang/rust/issues/111996
+
+------------------------
+
+The `diagnostic_namespace` feature permits customization of compilation errors.
+
+## diagnostic::on_unimplemented
+
+With [#114452] support for `diagnostic::on_unimplemented` was added.
+
+When used on a trait declaration, the following options are available:
+
+* `message` to customize the primary error message
+* `note` to add a customized note message to an error message
+* `label` to customize the label part of the error message
+
+The attribute will hint to the compiler to use these in error messages:
+```rust
+// some library
+#![feature(diagnostic_namespace)]
+
+#[diagnostic::on_unimplemented(
+    message = "cannot insert element",
+    label = "cannot be put into a table",
+    note = "see <link> for more information about the Table api"
+)]
+pub trait Element {
+    // ...
+}
+```
+
+```rust,compile_fail,E0277
+# #![feature(diagnostic_namespace)]
+#
+# #[diagnostic::on_unimplemented(
+#    message = "cannot insert element",
+#    label = "cannot be put into a table",
+#    note = "see <link> for more information about the Table api"
+# )]
+# pub trait Element {
+#    // ...
+# }
+# struct Table;
+# impl Table {
+#    fn insert<T: Element>(&self, element: T) {
+#        // ..
+#    }
+# }
+# fn main() {
+#    let table = Table;
+#    let element = ();
+// user code
+table.insert(element);
+# }
+```
+
+```text
+error[E0277]: cannot insert element
+  --> src/main.rs:24:18
+   |
+24 |     table.insert(element);
+   |           ------ ^^^^^^^ cannot be put into a table
+   |           |
+   |           required by a bound introduced by this call
+   |
+   = help: the trait `Element` is not implemented for `<type>`
+   = note: see <link> for more information about the Table api
+note: required by a bound in `Table::insert`
+  --> src/main.rs:15:18
+   |
+15 |     fn insert<T: Element>(&self, element: T) {
+   |                  ^^^^^^^ required by this bound in `Table::insert`
+
+For more information about this error, try `rustc --explain E0277`.
+```
+
+See [RFC 3368] for more information.
+
+[#114452]: https://github.com/rust-lang/rust/pull/114452
+[RFC 3368]: https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b9d7acee63c..e08318e4f54 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -521,7 +521,7 @@ fn clean_generic_param_def<'tcx>(
                 },
             )
         }
-        ty::GenericParamDefKind::Const { has_default, .. } => (
+        ty::GenericParamDefKind::Const { has_default, is_host_effect } => (
             def.name,
             GenericParamDefKind::Const {
                 ty: Box::new(clean_middle_ty(
@@ -541,6 +541,7 @@ fn clean_generic_param_def<'tcx>(
                     )),
                     false => None,
                 },
+                is_host_effect,
             },
         ),
     };
@@ -597,6 +598,7 @@ fn clean_generic_param<'tcx>(
                 ty: Box::new(clean_ty(ty, cx)),
                 default: default
                     .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
+                is_host_effect: cx.tcx.has_attr(param.def_id, sym::rustc_host),
             },
         ),
     };
@@ -2508,14 +2510,22 @@ fn clean_generic_args<'tcx>(
         let args = generic_args
             .args
             .iter()
-            .map(|arg| match arg {
-                hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
-                    GenericArg::Lifetime(clean_lifetime(*lt, cx))
-                }
-                hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
-                hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
-                hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+            .filter_map(|arg| {
+                Some(match arg {
+                    hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
+                        GenericArg::Lifetime(clean_lifetime(*lt, cx))
+                    }
+                    hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
+                    // FIXME(effects): This will still emit `<true>` for non-const impls of const traits
+                    hir::GenericArg::Const(ct)
+                        if cx.tcx.has_attr(ct.value.def_id, sym::rustc_host) =>
+                    {
+                        return None;
+                    }
+                    hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+                    hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+                })
             })
             .collect::<Vec<_>>()
             .into();
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index b891dc59cb1..517a51867cf 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1306,7 +1306,7 @@ impl WherePredicate {
 pub(crate) enum GenericParamDefKind {
     Lifetime { outlives: Vec<Lifetime> },
     Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
-    Const { ty: Box<Type>, default: Option<Box<String>> },
+    Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
 }
 
 impl GenericParamDefKind {
@@ -1326,9 +1326,10 @@ impl GenericParamDef {
         Self { name, kind: GenericParamDefKind::Lifetime { outlives: Vec::new() } }
     }
 
-    pub(crate) fn is_synthetic_type_param(&self) -> bool {
+    pub(crate) fn is_synthetic_param(&self) -> bool {
         match self.kind {
-            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
+            GenericParamDefKind::Lifetime { .. } => false,
+            GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect,
             GenericParamDefKind::Type { synthetic, .. } => synthetic,
         }
     }
@@ -2084,9 +2085,8 @@ impl Discriminant {
     pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
         self.expr.map(|body| rendered_const(tcx, body))
     }
-    /// Will always be a machine readable number, without underscores or suffixes.
-    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String {
-        print_evaluated_const(tcx, self.value, false).unwrap()
+    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
+        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
     }
 }
 
@@ -2331,7 +2331,7 @@ impl ConstantKind {
         match *self {
             ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
             ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
-                print_evaluated_const(tcx, def_id, true)
+                print_evaluated_const(tcx, def_id, true, true)
             }
         }
     }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 8388f722a7f..c5302570489 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -104,6 +104,10 @@ pub(crate) fn ty_args_to_args<'tcx>(
                     arg: index,
                 }),
             ))),
+            // FIXME(effects): this relies on the host effect being called `host`, which users could also name
+            // their const generics.
+            // FIXME(effects): this causes `host = true` and `host = false` generics to also be emitted.
+            GenericArgKind::Const(ct) if let ty::ConstKind::Param(p) = ct.kind() && p.name == sym::host => None,
             GenericArgKind::Const(ct) => {
                 Some(GenericArg::Const(Box::new(clean_middle_const(kind.rebind(ct), cx))))
             }
@@ -275,7 +279,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
 pub(crate) fn print_evaluated_const(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-    underscores_and_type: bool,
+    with_underscores: bool,
+    with_type: bool,
 ) -> Option<String> {
     tcx.const_eval_poly(def_id).ok().and_then(|val| {
         let ty = tcx.type_of(def_id).instantiate_identity();
@@ -284,7 +289,7 @@ pub(crate) fn print_evaluated_const(
             (mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
             (mir::ConstValue::Scalar(_), _) => {
                 let const_ = mir::Const::from_value(val, ty);
-                Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
+                Some(print_const_with_custom_print_scalar(tcx, const_, with_underscores, with_type))
             }
             _ => None,
         }
@@ -320,32 +325,37 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
 fn print_const_with_custom_print_scalar<'tcx>(
     tcx: TyCtxt<'tcx>,
     ct: mir::Const<'tcx>,
-    underscores_and_type: bool,
+    with_underscores: bool,
+    with_type: bool,
 ) -> String {
     // Use a slightly different format for integer types which always shows the actual value.
     // For all other types, fallback to the original `pretty_print_const`.
     match (ct, ct.ty().kind()) {
         (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
-            if underscores_and_type {
-                format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
+            let mut output = if with_underscores {
+                format_integer_with_underscore_sep(&int.to_string())
             } else {
                 int.to_string()
+            };
+            if with_type {
+                output += ui.name_str();
             }
+            output
         }
         (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
             let ty = ct.ty();
             let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
             let data = int.assert_bits(size);
             let sign_extended_data = size.sign_extend(data) as i128;
-            if underscores_and_type {
-                format!(
-                    "{}{}",
-                    format_integer_with_underscore_sep(&sign_extended_data.to_string()),
-                    i.name_str()
-                )
+            let mut output = if with_underscores {
+                format_integer_with_underscore_sep(&sign_extended_data.to_string())
             } else {
                 sign_extended_data.to_string()
+            };
+            if with_type {
+                output += i.name_str();
             }
+            output
         }
         _ => ct.to_string(),
     }
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 4c6e7dfb987..4ccb5f2be34 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -221,19 +221,25 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             _ => self.cache.stripped_mod,
         };
 
+        #[inline]
+        fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool {
+            let krate = def_id.krate;
+
+            cache.masked_crates.contains(&krate) || tcx.is_private_dep(krate)
+        }
+
         // If the impl is from a masked crate or references something from a
         // masked crate then remove it completely.
-        if let clean::ImplItem(ref i) = *item.kind {
-            if self.cache.masked_crates.contains(&item.item_id.krate())
+        if let clean::ImplItem(ref i) = *item.kind &&
+            (self.cache.masked_crates.contains(&item.item_id.krate())
                 || i.trait_
                     .as_ref()
-                    .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
+                    .map_or(false, |t| is_from_private_dep(self.tcx, self.cache, t.def_id()))
                 || i.for_
                     .def_id(self.cache)
-                    .map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
-            {
-                return None;
-            }
+                    .map_or(false, |d| is_from_private_dep(self.tcx, self.cache, d)))
+        {
+            return None;
         }
 
         // Propagate a trait method's documentation to all implementors of the
@@ -334,33 +340,37 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
                     // inserted later on when serializing the search-index.
-                    if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) {
+                    if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root())
+                        && let ty = item.type_()
+                        && (ty != ItemType::StructField
+                            || u16::from_str_radix(s.as_str(), 10).is_err())
+                    {
                         let desc =
                             short_markdown_summary(&item.doc_value(), &item.link_names(self.cache));
-                        let ty = item.type_();
-                        if ty != ItemType::StructField
-                            || u16::from_str_radix(s.as_str(), 10).is_err()
-                        {
-                            // In case this is a field from a tuple struct, we don't add it into
-                            // the search index because its name is something like "0", which is
-                            // not useful for rustdoc search.
-                            self.cache.search_index.push(IndexItem {
-                                ty,
-                                name: s,
-                                path: join_with_double_colon(path),
-                                desc,
-                                parent,
-                                parent_idx: None,
-                                search_type: get_function_type_for_search(
-                                    &item,
-                                    self.tcx,
-                                    clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
-                                    self.cache,
-                                ),
-                                aliases: item.attrs.get_doc_aliases(),
-                                deprecation: item.deprecation(self.tcx),
-                            });
-                        }
+                        // In case this is a field from a tuple struct, we don't add it into
+                        // the search index because its name is something like "0", which is
+                        // not useful for rustdoc search.
+                        self.cache.search_index.push(IndexItem {
+                            ty,
+                            name: s,
+                            path: join_with_double_colon(path),
+                            desc,
+                            parent,
+                            parent_idx: None,
+                            impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = self.cache.parent_stack.last() {
+                                item_id.as_def_id()
+                            } else {
+                                None
+                            },
+                            search_type: get_function_type_for_search(
+                                &item,
+                                self.tcx,
+                                clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
+                                self.cache,
+                            ),
+                            aliases: item.attrs.get_doc_aliases(),
+                            deprecation: item.deprecation(self.tcx),
+                        });
                     }
                 }
                 (Some(parent), None) if is_inherent_impl_item => {
@@ -371,6 +381,13 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                         parent,
                         item: item.clone(),
                         impl_generics,
+                        impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) =
+                            self.cache.parent_stack.last()
+                        {
+                            item_id.as_def_id()
+                        } else {
+                            None
+                        },
                     });
                 }
                 _ => {}
@@ -541,6 +558,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
 
 pub(crate) struct OrphanImplItem {
     pub(crate) parent: DefId,
+    pub(crate) impl_id: Option<DefId>,
     pub(crate) item: clean::Item,
     pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>,
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 1983bb11e5b..aa3f7184b4e 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -250,8 +250,7 @@ impl clean::Generics {
         cx: &'a Context<'tcx>,
     ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
-            let mut real_params =
-                self.params.iter().filter(|p| !p.is_synthetic_type_param()).peekable();
+            let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
             if real_params.peek().is_none() {
                 return Ok(());
             }
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 8c5871d9126..d4b4db0f3fd 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -17,6 +17,7 @@ pub(crate) struct Layout {
     pub(crate) external_html: ExternalHtml,
     pub(crate) default_settings: FxHashMap<String, String>,
     pub(crate) krate: String,
+    pub(crate) krate_version: String,
     /// The given user css file which allow to customize the generated
     /// documentation theme.
     pub(crate) css_file_extension: Option<PathBuf>,
@@ -31,6 +32,7 @@ pub(crate) struct Page<'a> {
     pub(crate) static_root_path: Option<&'a str>,
     pub(crate) description: &'a str,
     pub(crate) resource_suffix: &'a str,
+    pub(crate) rust_logo: bool,
 }
 
 impl<'a> Page<'a> {
@@ -54,9 +56,19 @@ struct PageLayout<'a> {
     themes: Vec<String>,
     sidebar: String,
     content: String,
-    krate_with_trailing_slash: String,
     rust_channel: &'static str,
     pub(crate) rustdoc_version: &'a str,
+    // same as layout.krate, except on top-level pages like
+    // Settings, Help, All Crates, and About Scraped Examples,
+    // where these things instead give Rustdoc name and version.
+    //
+    // These are separate from the variables used for the search
+    // engine, because "Rustdoc" isn't necessarily a crate in
+    // the current workspace.
+    display_krate: &'a str,
+    display_krate_with_trailing_slash: String,
+    display_krate_version_number: &'a str,
+    display_krate_version_extra: &'a str,
 }
 
 pub(crate) fn render<T: Print, S: Print>(
@@ -66,12 +78,26 @@ pub(crate) fn render<T: Print, S: Print>(
     t: T,
     style_files: &[StylePath],
 ) -> String {
+    let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
+
+    let (display_krate, display_krate_version, display_krate_with_trailing_slash) =
+        if page.root_path == "./" {
+            // top level pages use Rust branding
+            ("Rustdoc", rustdoc_version, String::new())
+        } else {
+            let display_krate_with_trailing_slash =
+                ensure_trailing_slash(&layout.krate).to_string();
+            (&layout.krate[..], &layout.krate_version[..], display_krate_with_trailing_slash)
+        };
     let static_root_path = page.get_static_root_path();
-    let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
+
+    // bootstrap passes in parts of the version separated by tabs, but other stuff might use spaces
+    let (display_krate_version_number, display_krate_version_extra) =
+        display_krate_version.split_once([' ', '\t']).unwrap_or((display_krate_version, ""));
+
     let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
     themes.sort();
 
-    let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
     let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
     let sidebar = Buffer::html().to_display(sidebar);
     PageLayout {
@@ -82,7 +108,10 @@ pub(crate) fn render<T: Print, S: Print>(
         themes,
         sidebar,
         content,
-        krate_with_trailing_slash,
+        display_krate,
+        display_krate_with_trailing_slash,
+        display_krate_version_number,
+        display_krate_version_extra,
         rust_channel: *crate::clean::utils::DOC_CHANNEL,
         rustdoc_version,
     }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 97714afaa45..bf8d1a80337 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -24,6 +24,7 @@ use super::{
     sidebar::{sidebar_module_like, Sidebar},
     AllTypes, LinkFromSrc, StylePath,
 };
+use crate::clean::utils::has_doc_flag;
 use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem};
 use crate::config::{ModuleSorting, RenderOptions};
 use crate::docfs::{DocFS, PathError};
@@ -277,6 +278,7 @@ impl<'tcx> Context<'tcx> {
                 title: &title,
                 description: &desc,
                 resource_suffix: &clone_shared.resource_suffix,
+                rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
             };
             let mut page_buffer = Buffer::html();
             print_item(self, it, &mut page_buffer, &page);
@@ -528,12 +530,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         if let Some(url) = playground_url {
             playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url });
         }
+        let krate_version = cache.crate_version.as_deref().unwrap_or_default();
         let mut layout = layout::Layout {
             logo: String::new(),
             favicon: String::new(),
             external_html,
             default_settings,
             krate: krate.name(tcx).to_string(),
+            krate_version: krate_version.to_string(),
             css_file_extension: extension_css,
             scrape_examples_extension: !call_locations.is_empty(),
         };
@@ -658,21 +662,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         let shared = Rc::clone(&self.shared);
         let mut page = layout::Page {
             title: "List of all items in this crate",
-            css_class: "mod",
+            css_class: "mod sys",
             root_path: "../",
             static_root_path: shared.static_root_path.as_deref(),
             description: "List of all items in this crate",
             resource_suffix: &shared.resource_suffix,
+            rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
         };
         let all = shared.all.replace(AllTypes::new());
         let mut sidebar = Buffer::html();
 
         let blocks = sidebar_module_like(all.item_sections());
         let bar = Sidebar {
-            title_prefix: "Crate ",
-            title: crate_name.as_str(),
+            title_prefix: "",
+            title: "",
             is_crate: false,
-            version: "",
+            is_mod: false,
             blocks: vec![blocks],
             path: String::new(),
         };
@@ -689,9 +694,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         shared.fs.write(final_file, v)?;
 
         // Generating settings page.
-        page.title = "Rustdoc settings";
+        page.title = "Settings";
         page.description = "Settings of Rustdoc";
         page.root_path = "./";
+        page.rust_logo = true;
 
         let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
         let v = layout::render(
@@ -739,9 +745,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         shared.fs.write(settings_file, v)?;
 
         // Generating help page.
-        page.title = "Rustdoc help";
+        page.title = "Help";
         page.description = "Documentation for Rustdoc";
         page.root_path = "./";
+        page.rust_logo = true;
 
         let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
         let v = layout::render(
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 3e671a64b54..49817f5eb64 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -54,7 +54,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{
     symbol::{sym, Symbol},
     BytePos, FileName, RealFileName,
@@ -102,6 +102,7 @@ pub(crate) struct IndexItem {
     pub(crate) desc: String,
     pub(crate) parent: Option<DefId>,
     pub(crate) parent_idx: Option<isize>,
+    pub(crate) impl_id: Option<DefId>,
     pub(crate) search_type: Option<IndexItemFunctionType>,
     pub(crate) aliases: Box<[Symbol]>,
     pub(crate) deprecation: Option<Deprecation>,
@@ -1877,7 +1878,7 @@ pub(crate) fn render_impl_summary(
     aliases: &[String],
 ) {
     let inner_impl = i.inner_impl();
-    let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx));
+    let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
     let aliases = if aliases.is_empty() {
         String::new()
     } else {
@@ -1994,21 +1995,35 @@ pub(crate) fn small_url_encode(s: String) -> String {
     }
 }
 
-fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String {
-    match trait_ {
-        Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))),
-        None => small_url_encode(format!("impl-{:#}", for_.print(cx))),
-    }
+fn get_id_for_impl<'tcx>(tcx: TyCtxt<'tcx>, impl_id: ItemId) -> String {
+    use rustc_middle::ty::print::with_forced_trimmed_paths;
+    let (type_, trait_) = match impl_id {
+        ItemId::Auto { trait_, for_ } => {
+            let ty = tcx.type_of(for_).skip_binder();
+            (ty, Some(ty::TraitRef::new(tcx, trait_, [ty])))
+        }
+        ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => {
+            match tcx.impl_subject(impl_id).skip_binder() {
+                ty::ImplSubject::Trait(trait_ref) => {
+                    (trait_ref.args[0].expect_ty(), Some(trait_ref))
+                }
+                ty::ImplSubject::Inherent(ty) => (ty, None),
+            }
+        }
+    };
+    with_forced_trimmed_paths!(small_url_encode(if let Some(trait_) = trait_ {
+        format!("impl-{trait_}-for-{type_}", trait_ = trait_.print_only_trait_path())
+    } else {
+        format!("impl-{type_}")
+    }))
 }
 
 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
     match *item.kind {
-        clean::ItemKind::ImplItem(ref i) => {
-            i.trait_.as_ref().map(|trait_| {
-                // Alternative format produces no URLs,
-                // so this parameter does nothing.
-                (format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx))
-            })
+        clean::ItemKind::ImplItem(ref i) if i.trait_.is_some() => {
+            // Alternative format produces no URLs,
+            // so this parameter does nothing.
+            Some((format!("{:#}", i.for_.print(cx)), get_id_for_impl(cx.tcx(), item.item_id)))
         }
         _ => None,
     }
@@ -2079,6 +2094,7 @@ impl ItemSection {
     const ALL: &'static [Self] = {
         use ItemSection::*;
         // NOTE: The order here affects the order in the UI.
+        // Keep this synchronized with addSidebarItems in main.js
         &[
             Reexports,
             PrimitiveTypes,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c6751c9585e..cd31493bf3f 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -5,10 +5,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
+use rustc_index::IndexVec;
 use rustc_middle::middle::stability;
+use rustc_middle::query::Key;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_target::abi::VariantIdx;
 use std::cell::{RefCell, RefMut};
 use std::cmp::Ordering;
 use std::fmt;
@@ -1247,6 +1250,9 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
         match inner_type {
             clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => {
                 let variants_iter = || variants.iter().filter(|i| !i.is_stripped());
+                let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
+                let enum_def_id = ty.ty_adt_id().unwrap();
+
                 wrap_item(w, |w| {
                     let variants_len = variants.len();
                     let variants_count = variants_iter().count();
@@ -1257,13 +1263,14 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
                         w,
                         cx,
                         Some(&t.generics),
-                        variants_iter(),
+                        &variants,
                         variants_count,
                         has_stripped_entries,
                         *is_non_exhaustive,
+                        enum_def_id,
                     )
                 });
-                item_variants(w, cx, it, variants_iter());
+                item_variants(w, cx, it, &variants, enum_def_id);
             }
             clean::TypeAliasInnerType::Union { fields } => {
                 wrap_item(w, |w| {
@@ -1416,36 +1423,90 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
             it.name.unwrap(),
             e.generics.print(cx),
         );
+
         render_enum_fields(
             w,
             cx,
             Some(&e.generics),
-            e.variants(),
+            &e.variants,
             count_variants,
             e.has_stripped_entries(),
             it.is_non_exhaustive(),
+            it.def_id().unwrap(),
         );
     });
 
     write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
 
     if count_variants != 0 {
-        item_variants(w, cx, it, e.variants());
+        item_variants(w, cx, it, &e.variants, it.def_id().unwrap());
     }
     let def_id = it.item_id.expect_def_id();
     write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
     write!(w, "{}", document_type_layout(cx, def_id));
 }
 
-fn render_enum_fields<'a>(
+/// It'll return false if any variant is not a C-like variant. Otherwise it'll return true if at
+/// least one of them has an explicit discriminant or if the enum has `#[repr(C)]` or an integer
+/// `repr`.
+fn should_show_enum_discriminant(
+    cx: &Context<'_>,
+    enum_def_id: DefId,
+    variants: &IndexVec<VariantIdx, clean::Item>,
+) -> bool {
+    let mut has_variants_with_value = false;
+    for variant in variants {
+        if let clean::VariantItem(ref var) = *variant.kind &&
+            matches!(var.kind, clean::VariantKind::CLike)
+        {
+            has_variants_with_value |= var.discriminant.is_some();
+        } else {
+            return false;
+        }
+    }
+    if has_variants_with_value {
+        return true;
+    }
+    let repr = cx.tcx().adt_def(enum_def_id).repr();
+    repr.c() || repr.int.is_some()
+}
+
+fn display_c_like_variant(
+    w: &mut Buffer,
+    cx: &mut Context<'_>,
+    item: &clean::Item,
+    variant: &clean::Variant,
+    index: VariantIdx,
+    should_show_enum_discriminant: bool,
+    enum_def_id: DefId,
+) {
+    let name = item.name.unwrap();
+    if let Some(ref value) = variant.discriminant {
+        write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true));
+    } else if should_show_enum_discriminant {
+        let adt_def = cx.tcx().adt_def(enum_def_id);
+        let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
+        if discr.ty.is_signed() {
+            write!(w, "{} = {}", name.as_str(), discr.val as i128);
+        } else {
+            write!(w, "{} = {}", name.as_str(), discr.val);
+        }
+    } else {
+        w.write_str(name.as_str());
+    }
+}
+
+fn render_enum_fields(
     mut w: &mut Buffer,
     cx: &mut Context<'_>,
     g: Option<&clean::Generics>,
-    variants: impl Iterator<Item = &'a clean::Item>,
+    variants: &IndexVec<VariantIdx, clean::Item>,
     count_variants: usize,
     has_stripped_entries: bool,
     is_non_exhaustive: bool,
+    enum_def_id: DefId,
 ) {
+    let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants);
     if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) {
         // If there wasn't a `where` clause, we add a whitespace.
         w.write_str(" ");
@@ -1461,15 +1522,24 @@ fn render_enum_fields<'a>(
             toggle_open(&mut w, format_args!("{count_variants} variants"));
         }
         const TAB: &str = "    ";
-        for v in variants {
+        for (index, v) in variants.iter_enumerated() {
+            if v.is_stripped() {
+                continue;
+            }
             w.write_str(TAB);
-            let name = v.name.unwrap();
             match *v.kind {
-                // FIXME(#101337): Show discriminant
                 clean::VariantItem(ref var) => match var.kind {
-                    clean::VariantKind::CLike => w.write_str(name.as_str()),
+                    clean::VariantKind::CLike => display_c_like_variant(
+                        w,
+                        cx,
+                        v,
+                        var,
+                        index,
+                        should_show_enum_discriminant,
+                        enum_def_id,
+                    ),
                     clean::VariantKind::Tuple(ref s) => {
-                        write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
+                        write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s));
                     }
                     clean::VariantKind::Struct(ref s) => {
                         render_struct(w, v, None, None, &s.fields, TAB, false, cx);
@@ -1490,11 +1560,12 @@ fn render_enum_fields<'a>(
     }
 }
 
-fn item_variants<'a>(
+fn item_variants(
     w: &mut Buffer,
     cx: &mut Context<'_>,
     it: &clean::Item,
-    variants: impl Iterator<Item = &'a clean::Item>,
+    variants: &IndexVec<VariantIdx, clean::Item>,
+    enum_def_id: DefId,
 ) {
     let tcx = cx.tcx();
     write!(
@@ -1507,7 +1578,11 @@ fn item_variants<'a>(
         document_non_exhaustive_header(it),
         document_non_exhaustive(it)
     );
-    for variant in variants {
+    let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants);
+    for (index, variant) in variants.iter_enumerated() {
+        if variant.is_stripped() {
+            continue;
+        }
         let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
         write!(
             w,
@@ -1522,7 +1597,22 @@ fn item_variants<'a>(
             it.const_stable_since(tcx),
             " rightside",
         );
-        write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
+        w.write_str("<h3 class=\"code-header\">");
+        if let clean::VariantItem(ref var) = *variant.kind &&
+            let clean::VariantKind::CLike = var.kind
+        {
+            display_c_like_variant(
+                w,
+                cx,
+                variant,
+                var,
+                index,
+                should_show_enum_discriminant,
+                enum_def_id,
+            );
+        } else {
+            w.write_str(variant.name.unwrap().as_str());
+        }
 
         let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
 
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 78c443b2257..af1dab59496 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -12,7 +12,7 @@ use crate::formats::cache::{Cache, OrphanImplItem};
 use crate::formats::item_type::ItemType;
 use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
-use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
+use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
 
 /// Builds the search index from the collected metadata
 pub(crate) fn build_index<'tcx>(
@@ -26,7 +26,8 @@ pub(crate) fn build_index<'tcx>(
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
-    for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
+    for &OrphanImplItem { impl_id, parent, ref item, ref impl_generics } in &cache.orphan_impl_items
+    {
         if let Some((fqp, _)) = cache.paths.get(&parent) {
             let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
             cache.search_index.push(IndexItem {
@@ -36,6 +37,7 @@ pub(crate) fn build_index<'tcx>(
                 desc,
                 parent: Some(parent),
                 parent_idx: None,
+                impl_id,
                 search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache),
                 aliases: item.attrs.get_doc_aliases(),
                 deprecation: item.deprecation(tcx),
@@ -222,6 +224,29 @@ pub(crate) fn build_index<'tcx>(
         })
         .collect();
 
+    // Find associated items that need disambiguators
+    let mut associated_item_duplicates = FxHashMap::<(isize, ItemType, Symbol), usize>::default();
+
+    for &item in &crate_items {
+        if item.impl_id.is_some() && let Some(parent_idx) = item.parent_idx {
+            let count = associated_item_duplicates
+                .entry((parent_idx, item.ty, item.name))
+                .or_insert(0);
+            *count += 1;
+        }
+    }
+
+    let associated_item_disambiguators = crate_items
+        .iter()
+        .enumerate()
+        .filter_map(|(index, item)| {
+            let impl_id = ItemId::DefId(item.impl_id?);
+            let parent_idx = item.parent_idx?;
+            let count = *associated_item_duplicates.get(&(parent_idx, item.ty, item.name))?;
+            if count > 1 { Some((index, render::get_id_for_impl(tcx, impl_id))) } else { None }
+        })
+        .collect::<Vec<_>>();
+
     struct CrateData<'a> {
         doc: String,
         items: Vec<&'a IndexItem>,
@@ -230,6 +255,8 @@ pub(crate) fn build_index<'tcx>(
         //
         // To be noted: the `usize` elements are indexes to `items`.
         aliases: &'a BTreeMap<String, Vec<usize>>,
+        // Used when a type has more than one impl with an associated item with the same name.
+        associated_item_disambiguators: &'a Vec<(usize, String)>,
     }
 
     struct Paths {
@@ -382,6 +409,7 @@ pub(crate) fn build_index<'tcx>(
             crate_data.serialize_field("f", &functions)?;
             crate_data.serialize_field("c", &deprecated)?;
             crate_data.serialize_field("p", &paths)?;
+            crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
             }
@@ -398,6 +426,7 @@ pub(crate) fn build_index<'tcx>(
             items: crate_items,
             paths: crate_paths,
             aliases: &aliases,
+            associated_item_disambiguators: &associated_item_disambiguators,
         })
         .expect("failed serde conversion")
         // All these `replace` calls are because we have to go through JS string for JSON content.
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 76f63c6f63e..fb429f237e3 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -19,7 +19,7 @@ pub(super) struct Sidebar<'a> {
     pub(super) title_prefix: &'static str,
     pub(super) title: &'a str,
     pub(super) is_crate: bool,
-    pub(super) version: &'a str,
+    pub(super) is_mod: bool,
     pub(super) blocks: Vec<LinkBlock<'a>>,
     pub(super) path: String,
 }
@@ -99,12 +99,12 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
         || it.is_primitive()
         || it.is_union()
         || it.is_enum()
-        || it.is_mod()
+        // crate title is displayed as part of logo lockup
+        || (it.is_mod() && !it.is_crate())
         || it.is_type_alias()
     {
         (
             match *it.kind {
-                clean::ModuleItem(..) if it.is_crate() => "Crate ",
                 clean::ModuleItem(..) => "Module ",
                 _ => "",
             },
@@ -113,14 +113,22 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
     } else {
         ("", "")
     };
-    let version =
-        if it.is_crate() { cx.cache().crate_version.as_deref().unwrap_or_default() } else { "" };
-    let path: String = if !it.is_mod() {
-        cx.current.iter().map(|s| s.as_str()).intersperse("::").collect()
+    // need to show parent path header if:
+    //   - it's a child module, instead of the crate root
+    //   - there's a sidebar section for the item itself
+    //
+    // otherwise, the parent path header is redundant with the big crate
+    // branding area at the top of the sidebar
+    let sidebar_path =
+        if it.is_mod() { &cx.current[..cx.current.len() - 1] } else { &cx.current[..] };
+    let path: String = if sidebar_path.len() > 1 || !title.is_empty() {
+        let path = sidebar_path.iter().map(|s| s.as_str()).intersperse("::").collect();
+        if sidebar_path.len() == 1 { format!("crate {path}") } else { path }
     } else {
         "".into()
     };
-    let sidebar = Sidebar { title_prefix, title, is_crate: it.is_crate(), version, blocks, path };
+    let sidebar =
+        Sidebar { title_prefix, title, is_mod: it.is_mod(), is_crate: it.is_crate(), blocks, path };
     sidebar.render_into(buffer).unwrap();
 }
 
@@ -503,8 +511,7 @@ fn sidebar_render_assoc_items(
             .iter()
             .filter_map(|it| {
                 let trait_ = it.inner_impl().trait_.as_ref()?;
-                let encoded =
-                    id_map.derive(super::get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
+                let encoded = id_map.derive(super::get_id_for_impl(cx.tcx(), it.impl_item.item_id));
 
                 let prefix = match it.inner_impl().polarity {
                     ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index e824651e727..e68d5ab2fbd 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -336,11 +336,12 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
             let dst = cx.dst.join("index.html");
             let page = layout::Page {
                 title: "Index of crates",
-                css_class: "mod",
+                css_class: "mod sys",
                 root_path: "./",
                 static_root_path: shared.static_root_path.as_deref(),
                 description: "List of crates",
                 resource_suffix: &shared.resource_suffix,
+                rust_logo: true,
             };
 
             let content = format!(
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 1d6eafe51b9..4a218b9b37c 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -1,4 +1,5 @@
 use crate::clean;
+use crate::clean::utils::has_doc_flag;
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::html::format;
@@ -13,6 +14,7 @@ use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::FileName;
+use rustc_span::sym;
 
 use std::cell::RefCell;
 use std::ffi::OsStr;
@@ -231,6 +233,7 @@ impl SourceCollector<'_, '_> {
             static_root_path: shared.static_root_path.as_deref(),
             description: &desc,
             resource_suffix: &shared.resource_suffix,
+            rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
         };
         let v = layout::render(
             &shared.layout,
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 47f9e650281..e2b4cc50dd5 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -461,19 +461,9 @@ img {
 	display: none !important;
 }
 
-.sidebar .logo-container {
-	margin-top: 10px;
-	margin-bottom: 10px;
-	text-align: center;
-}
-
-.version {
-	overflow-wrap: break-word;
-}
-
 .logo-container > img {
-	height: 100px;
-	width: 100px;
+	height: 48px;
+	width: 48px;
 }
 
 ul.block, .block li {
@@ -502,6 +492,7 @@ ul.block, .block li {
 }
 
 .sidebar-elems,
+.sidebar > .version,
 .sidebar > h2 {
 	padding-left: 24px;
 }
@@ -510,6 +501,8 @@ ul.block, .block li {
 	color: var(--sidebar-link-color);
 }
 .sidebar .current,
+.sidebar .current a,
+.sidebar-crate a.logo-container:hover + h2 a,
 .sidebar a:hover:not(.logo-container) {
 	background-color: var(--sidebar-current-link-background-color);
 }
@@ -524,6 +517,75 @@ ul.block, .block li {
 	overflow: hidden;
 }
 
+.sidebar-crate {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	/* there's a 10px padding at the top of <main>, and a 4px margin at the
+		top of the search form. To line them up, add them. */
+	margin: 14px 32px 1rem;
+	row-gap: 10px;
+	column-gap: 32px;
+	flex-wrap: wrap;
+}
+
+.sidebar-crate h2 {
+	flex-grow: 1;
+	/* This setup with the margins and row-gap is designed to make flex-wrap
+		work the way we want. If they're in the side-by-side lockup, there
+		should be a 16px margin to the left of the logo (visually the same as
+		the 24px one on everything else, which are not giant circles) and 8px
+		between it and the crate's name and version. When they're line wrapped,
+		the logo needs to have the same margin on both sides of itself (to
+		center properly) and the crate name and version need 24px on their
+		left margin. */
+	margin: 0 -8px;
+	/* To align this with the search bar, it should not be centered, even when
+		the logo is. */
+	align-self: start;
+}
+
+.sidebar-crate .logo-container {
+	/* The logo is expected to have 8px "slop" along its edges, so we can optically
+		center it. */
+	margin: 0 -16px 0 -16px;
+	text-align: center;
+}
+
+.sidebar-crate h2 a {
+	display: block;
+	margin: 0 calc(-24px + 0.25rem) 0 -0.5rem;
+	/* Align the sidebar crate link with the search bar, which have different
+		font sizes.
+
+		|        | font-size | line-height | total line-height | padding-y |     total    |
+		|:-------|----------:|------------:|------------------:|----------:|-------------:|
+		| crate  |  1.375rem |        1.25 |           1.72rem |         x |   2x+1.72rem |
+		| search |      1rem |        1.15 |           1.15rem |       8px | 1.15rem+16px |
+
+		2x + 1.72rem = 1.15rem + 16px
+		2x = 1.15rem + 16px - 1.72rem
+		2x = 16px - 0.57rem
+		x = ( 16px - 0.57rem ) / 2
+	*/
+	padding: calc( ( 16px - 0.57rem ) / 2 ) 0.25rem;
+	padding-left: 0.5rem;
+}
+
+.sidebar-crate h2 .version {
+	display: block;
+	font-weight: normal;
+	font-size: 1rem;
+	overflow-wrap: break-word;
+	/* opposite of the link padding, cut in half again */
+	margin-top: calc( ( -16px + 0.57rem ) / 2 );
+}
+
+.sidebar-crate + .version {
+	margin-top: -1rem;
+	margin-bottom: 1rem;
+}
+
 .mobile-topbar {
 	display: none;
 }
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index eb256455b08..2e9897ef82b 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -51,9 +51,14 @@ function setMobileTopbar() {
     // but with the current code it's hard to get the right information in the right place.
     const mobileTopbar = document.querySelector(".mobile-topbar");
     const locationTitle = document.querySelector(".sidebar h2.location");
-    if (mobileTopbar && locationTitle) {
+    if (mobileTopbar) {
         const mobileTitle = document.createElement("h2");
-        mobileTitle.innerHTML = locationTitle.innerHTML;
+        mobileTitle.className = "location";
+        if (hasClass(document.body, "crate")) {
+            mobileTitle.innerText = `Crate ${window.currentCrate}`;
+        } else if (locationTitle) {
+            mobileTitle.innerHTML = locationTitle.innerHTML;
+        }
         mobileTopbar.appendChild(mobileTitle);
     }
 }
@@ -354,6 +359,34 @@ function preLoadCss(cssUrl) {
                 expandSection(pageId);
             }
         }
+        if (savedHash.startsWith("impl-")) {
+            // impl-disambiguated links, used by the search engine
+            // format: impl-X[-for-Y]/method.WHATEVER
+            // turn this into method.WHATEVER[-NUMBER]
+            const splitAt = savedHash.indexOf("/");
+            if (splitAt !== -1) {
+                const implId = savedHash.slice(0, splitAt);
+                const assocId = savedHash.slice(splitAt + 1);
+                const implElem = document.getElementById(implId);
+                if (implElem && implElem.parentElement.tagName === "SUMMARY" &&
+                    implElem.parentElement.parentElement.tagName === "DETAILS") {
+                    onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
+                        `[id^="${assocId}"]`),
+                        item => {
+                            const numbered = /([^-]+)-([0-9]+)/.exec(item.id);
+                            if (item.id === assocId || (numbered && numbered[1] === assocId)) {
+                                openParentDetails(item);
+                                item.scrollIntoView();
+                                // Let the section expand itself before trying to highlight
+                                setTimeout(() => {
+                                    window.location.replace("#" + item.id);
+                                }, 0);
+                            }
+                        }
+                    );
+                }
+            }
+        }
     }
 
     function onHashChange(ev) {
@@ -452,22 +485,27 @@ function preLoadCss(cssUrl) {
                 return;
             }
 
+            const modpath = hasClass(document.body, "mod") ? "../" : "";
+
             const h3 = document.createElement("h3");
-            h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
+            h3.innerHTML = `<a href="${modpath}index.html#${id}">${longty}</a>`;
             const ul = document.createElement("ul");
             ul.className = "block " + shortty;
 
             for (const name of filtered) {
                 let path;
                 if (shortty === "mod") {
-                    path = name + "/index.html";
+                    path = `${modpath}${name}/index.html`;
                 } else {
-                    path = shortty + "." + name + ".html";
+                    path = `${modpath}${shortty}.${name}.html`;
+                }
+                let current_page = document.location.href.toString();
+                if (current_page.endsWith("/")) {
+                    current_page += "index.html";
                 }
-                const current_page = document.location.href.split("/").pop();
                 const link = document.createElement("a");
                 link.href = path;
-                if (path === current_page) {
+                if (link.href === current_page) {
                     link.className = "current";
                 }
                 link.textContent = name;
@@ -480,19 +518,33 @@ function preLoadCss(cssUrl) {
         }
 
         if (sidebar) {
+            // keep this synchronized with ItemSection::ALL in html/render/mod.rs
+            // Re-exports aren't shown here, because they don't have child pages
+            //block("reexport", "reexports", "Re-exports");
             block("primitive", "primitives", "Primitive Types");
             block("mod", "modules", "Modules");
             block("macro", "macros", "Macros");
             block("struct", "structs", "Structs");
             block("enum", "enums", "Enums");
-            block("union", "unions", "Unions");
             block("constant", "constants", "Constants");
             block("static", "static", "Statics");
             block("trait", "traits", "Traits");
             block("fn", "functions", "Functions");
             block("type", "types", "Type Aliases");
+            block("union", "unions", "Unions");
+            // No point, because these items don't appear in modules
+            //block("impl", "impls", "Implementations");
+            //block("tymethod", "tymethods", "Type Methods");
+            //block("method", "methods", "Methods");
+            //block("structfield", "fields", "Fields");
+            //block("variant", "variants", "Variants");
+            //block("associatedtype", "associated-types", "Associated Types");
+            //block("associatedconstant", "associated-consts", "Associated Constants");
             block("foreigntype", "foreign-types", "Foreign Types");
             block("keyword", "keywords", "Keywords");
+            block("opaque", "opaque-types", "Opaque Types");
+            block("attr", "attributes", "Attribute Macros");
+            block("derive", "derives", "Derive Macros");
             block("traitalias", "trait-aliases", "Trait Aliases");
         }
     }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 7a282a99e9c..48c9a53a283 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1752,6 +1752,7 @@ function initSearch(rawSearchIndex) {
                 type: item.type,
                 is_alias: true,
                 deprecated: item.deprecated,
+                implDisambiguator: item.implDisambiguator,
             };
         }
 
@@ -2218,7 +2219,7 @@ function initSearch(rawSearchIndex) {
             href = ROOT_PATH + name + "/index.html";
         } else if (item.parent !== undefined) {
             const myparent = item.parent;
-            let anchor = "#" + type + "." + name;
+            let anchor = type + "." + name;
             const parentType = itemTypes[myparent.ty];
             let pageType = parentType;
             let pageName = myparent.name;
@@ -2232,16 +2233,19 @@ function initSearch(rawSearchIndex) {
                 const enumName = item.path.substr(enumNameIdx + 2);
                 path = item.path.substr(0, enumNameIdx);
                 displayPath = path + "::" + enumName + "::" + myparent.name + "::";
-                anchor = "#variant." + myparent.name + ".field." + name;
+                anchor = "variant." + myparent.name + ".field." + name;
                 pageType = "enum";
                 pageName = enumName;
             } else {
                 displayPath = path + "::" + myparent.name + "::";
             }
+            if (item.implDisambiguator !== null) {
+                anchor = item.implDisambiguator + "/" + anchor;
+            }
             href = ROOT_PATH + path.replace(/::/g, "/") +
                 "/" + pageType +
                 "." + pageName +
-                ".html" + anchor;
+                ".html#" + anchor;
         } else {
             displayPath = item.path + "::";
             href = ROOT_PATH + item.path.replace(/::/g, "/") +
@@ -2727,6 +2731,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\
              * Types are also represented as arrays; the first item is an index into the `p`
              * array, while the second is a list of types representing any generic parameters.
              *
+             * b[i] contains an item's impl disambiguator. This is only present if an item
+             * is defined in an impl block and, the impl block's type has more than one associated
+             * item with the same name.
+             *
              * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
              * points into the n/t/d/q/i/f arrays.
              *
@@ -2746,6 +2754,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
              *   i: Array<Number>,
              *   f: Array<RawFunctionSearchType>,
              *   p: Array<Object>,
+             *   b: Array<[Number, String]>,
              *   c: Array<Number>
              * }}
              */
@@ -2766,6 +2775,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                 id: id,
                 normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
                 deprecated: null,
+                implDisambiguator: null,
             };
             id += 1;
             searchIndex.push(crateRow);
@@ -2789,6 +2799,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             const itemFunctionSearchTypes = crateCorpus.f;
             // an array of (Number) indices for the deprecated items
             const deprecatedItems = new Set(crateCorpus.c);
+            // an array of (Number) indices for the deprecated items
+            const implDisambiguator = new Map(crateCorpus.b);
             // an array of [(Number) item type,
             //              (String) name]
             const paths = crateCorpus.p;
@@ -2849,6 +2861,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                     id: id,
                     normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
                     deprecated: deprecatedItems.has(i),
+                    implDisambiguator: implDisambiguator.has(i) ? implDisambiguator.get(i) : null,
                 };
                 id += 1;
                 searchIndex.push(row);
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 579c782be09..ebf817673bf 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -42,6 +42,8 @@
     <script defer src="{{page.root_path|safe}}src-files{{page.resource_suffix}}.js"></script> {# #}
     {% else if !page.css_class.contains("mod") %}
     <script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {# #}
+    {% else if !page.css_class.contains("sys") %}
+    <script defer src="../sidebar-items{{page.resource_suffix}}.js"></script> {# #}
     {% endif %}
     <script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {# #}
     {% if layout.scrape_examples_extension %}
@@ -77,36 +79,51 @@
     {% if page.css_class != "src" %}
     <nav class="mobile-topbar"> {# #}
         <button class="sidebar-menu-toggle">&#9776;</button> {# #}
-        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
-        {% if !layout.logo.is_empty() %}
-            <img src="{{layout.logo}}" alt="logo"> {# #}
-        {% else %}
-            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+        {% if !layout.logo.is_empty() || page.rust_logo %}
+        <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
+        {% if page.rust_logo %}
+            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt=""> {# #}
+        {% else if !layout.logo.is_empty() %}
+            <img src="{{layout.logo}}" alt=""> {# #}
         {% endif %}
         </a> {# #}
+        {% endif %}
     </nav>
     {% endif %}
     <nav class="sidebar"> {# #}
         {% if page.css_class != "src" %}
-        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
-            {% if !layout.logo.is_empty() %}
-                <img src="{{layout.logo}}" alt="logo"> {# #}
-            {% else %}
-                <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+        <div class="sidebar-crate">
+            {% if !layout.logo.is_empty() || page.rust_logo %}
+            <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
+                {% if page.rust_logo %}
+                    <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+                {% else if !layout.logo.is_empty() %}
+                    <img src="{{layout.logo}}" alt="logo"> {# #}
+                {% endif %}
+            </a> {# #}
             {% endif %}
-        </a> {# #}
+            <h2> {# #}
+                <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #}
+                {% if !display_krate_version_number.is_empty() %}
+                    <span class="version">{{+ display_krate_version_number}}</span>
+                {% endif %}
+            </h2> {# #}
+        </div> {# #}
+        {% if !display_krate_version_extra.is_empty() %}
+        <div class="version">{{+ display_krate_version_extra}}</div> {# #}
+        {% endif %}
         {% endif %}
         {{ sidebar|safe }}
     </nav> {# #}
     <main> {# #}
         {% if page.css_class != "src" %}<div class="width-limiter">{% endif %}
             <nav class="sub"> {# #}
-                {% if page.css_class == "src" %}
-                <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
-                    {% if !layout.logo.is_empty() %}
-                        <img src="{{layout.logo}}" alt="logo"> {# #}
-                    {% else %}
-                        <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+                {% if page.css_class == "src" && (!layout.logo.is_empty() || page.rust_logo) %}
+                <a class="sub-logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
+                    {% if page.rust_logo %}
+                    <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="{{display_krate}}"> {# #}
+                    {% else if !layout.logo.is_empty() %}
+                        <img src="{{layout.logo}}" alt="{{display_krate}}"> {# #}
                     {% endif %}
                 </a> {# #}
                 {% endif %}
diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html
index 01d476ad29f..a99198141e2 100644
--- a/src/librustdoc/html/templates/sidebar.html
+++ b/src/librustdoc/html/templates/sidebar.html
@@ -6,9 +6,6 @@
 <div class="sidebar-elems">
     {% if is_crate %}
         <ul class="block">
-            {% if !version.is_empty() %}
-                <li class="version">Version {{+ version}}</li>
-            {% endif %}
             <li><a id="all-types" href="all.html">All Items</a></li> {# #}
         </ul>
     {% endif %}
@@ -32,6 +29,6 @@
         </section>
     {% endif %}
     {% if !path.is_empty() %}
-        <h2><a href="index.html">In {{+ path}}</a></h2>
+        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path}}</a></h2>
     {% endif %}
 </div>
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 472cde51be5..1420d108664 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -453,7 +453,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
                 default: default.map(|x| (*x).into_tcx(tcx)),
                 synthetic,
             },
-            Const { ty, default } => GenericParamDefKind::Const {
+            Const { ty, default, is_host_effect: _ } => GenericParamDefKind::Const {
                 type_: (*ty).into_tcx(tcx),
                 default: default.map(|x| *x),
             },
@@ -491,12 +491,14 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
                                 default: default.map(|ty| (*ty).into_tcx(tcx)),
                                 synthetic,
                             },
-                            clean::GenericParamDefKind::Const { ty, default } => {
-                                GenericParamDefKind::Const {
-                                    type_: (*ty).into_tcx(tcx),
-                                    default: default.map(|d| *d),
-                                }
-                            }
+                            clean::GenericParamDefKind::Const {
+                                ty,
+                                default,
+                                is_host_effect: _,
+                            } => GenericParamDefKind::Const {
+                                type_: (*ty).into_tcx(tcx),
+                                default: default.map(|d| *d),
+                            },
                         };
                         GenericParamDef { name, kind }
                     })
@@ -744,7 +746,7 @@ impl FromWithTcx<clean::Discriminant> for Discriminant {
             // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
             // the expr is always some.
             expr: disr.expr(tcx).unwrap(),
-            value: disr.value(tcx),
+            value: disr.value(tcx, false),
         }
     }
 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index fc2acb6eaa3..67f5ea5d98b 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -6,6 +6,7 @@
 #![feature(array_methods)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
+#![feature(if_let_guard)]
 #![feature(impl_trait_in_assoc_type)]
 #![feature(iter_intersperse)]
 #![feature(lazy_cell)]
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 794d0a82547f3081044c0aca7b6083733ce5134
+Subproject 6fa6fdc7606cfa664f9bee2fb33ee2ed904f4e8
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index ed9189a1804..f0994695565 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
         if !in_external_macro(cx.sess(), expr.span)
             && (
                 matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
-                    || cx.tcx.features().active(sym!(const_float_classify))
+                    || cx.tcx.features().declared(sym!(const_float_classify))
             ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
             && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
             && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index cb65360d129..f929bec9583 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -31,7 +31,7 @@ LL |     const VAL: T;
    |     ------------ `VAL` from trait
 ...
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 269d9384376..948439d6e79 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -322,7 +322,15 @@ impl TestProps {
                 );
 
                 if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
-                    self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
+                    self.compile_flags.extend(
+                        flags
+                            .split("'")
+                            .enumerate()
+                            .flat_map(|(i, f)| {
+                                if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }
+                            })
+                            .map(|s| s.to_owned()),
+                    );
                 }
                 if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
                     panic!("`compiler-flags` directive should be spelled `compile-flags`");
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 2b7a4387ceb..4a40fb55f5c 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -241,8 +241,8 @@ impl CachedNeedsConditions {
             profiler_support: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(),
             xray: config.target_cfg().xray,
 
-            // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
-            // whether `rust-lld` is present in the compiler under test.
+            // For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`),
+            // we need to find whether `rust-lld` is present in the compiler under test.
             //
             // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For
             // example:
diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs
index b5e977b2637..da94e686f38 100644
--- a/src/tools/lld-wrapper/src/main.rs
+++ b/src/tools/lld-wrapper/src/main.rs
@@ -4,8 +4,8 @@
 //! two arguments the `<flavor>` command line interface is used to process the remaining arguments.
 //! If no `-flavor` argument is present the flavor is determined by the executable name.
 //!
-//! In Rust with `-Z gcc-ld=lld` we have gcc or clang invoke rust-lld. Since there is no way to
-//! make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation
+//! With `-Clink-self-contained=+linker` we have gcc or clang invoke rust-lld. Since there is no way
+//! to make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation
 //! and since Windows does not support symbolic links for files this wrapper is used in place of a
 //! symbolic link. It execs `../rust-lld -flavor <flavor>` by propagating the flavor argument
 //! obtained from the wrapper's name as the first two arguments.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 8f0a0a045ab..5e10427d171 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-4ea5190026dbc1302b644d938e68bc6843cb8b24
+3d575a2f2ef8a6eb99064bb31c16feb8d508f1ee
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 930fa053d20..4cb1e7a826b 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1001,6 +1001,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
         ecx.binary_ptr_op(bin_op, left, right)
     }
 
+    #[inline(always)]
+    fn generate_nan<
+        F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F2>,
+        F2: rustc_apfloat::Float,
+    >(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        inputs: &[F1],
+    ) -> F2 {
+        ecx.generate_nan(inputs)
+    }
+
     fn thread_local_static_base_pointer(
         ecx: &mut MiriInterpCx<'mir, 'tcx>,
         def_id: DefId,
diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs
index 1faf8f9fc12..e5a437f95f0 100644
--- a/src/tools/miri/src/operator.rs
+++ b/src/tools/miri/src/operator.rs
@@ -1,20 +1,16 @@
+use std::iter;
+
 use log::trace;
 
+use rand::{seq::IteratorRandom, Rng};
+use rustc_apfloat::{Float, FloatConvert};
 use rustc_middle::mir;
 use rustc_target::abi::Size;
 
 use crate::*;
 
-pub trait EvalContextExt<'tcx> {
-    fn binary_ptr_op(
-        &self,
-        bin_op: mir::BinOp,
-        left: &ImmTy<'tcx, Provenance>,
-        right: &ImmTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)>;
-}
-
-impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     fn binary_ptr_op(
         &self,
         bin_op: mir::BinOp,
@@ -23,12 +19,13 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
     ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> {
         use rustc_middle::mir::BinOp::*;
 
+        let this = self.eval_context_ref();
         trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
 
         Ok(match bin_op {
             Eq | Ne | Lt | Le | Gt | Ge => {
                 assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for`
-                let size = self.pointer_size();
+                let size = this.pointer_size();
                 // Just compare the bits. ScalarPairs are compared lexicographically.
                 // We thus always compare pairs and simply fill scalars up with 0.
                 let left = match **left {
@@ -50,7 +47,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
                     Ge => left >= right,
                     _ => bug!(),
                 };
-                (ImmTy::from_bool(res, *self.tcx), false)
+                (ImmTy::from_bool(res, *this.tcx), false)
             }
 
             // Some more operations are possible with atomics.
@@ -58,26 +55,67 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
             Add | Sub | BitOr | BitAnd | BitXor => {
                 assert!(left.layout.ty.is_unsafe_ptr());
                 assert!(right.layout.ty.is_unsafe_ptr());
-                let ptr = left.to_scalar().to_pointer(self)?;
+                let ptr = left.to_scalar().to_pointer(this)?;
                 // We do the actual operation with usize-typed scalars.
-                let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize);
+                let left = ImmTy::from_uint(ptr.addr().bytes(), this.machine.layouts.usize);
                 let right = ImmTy::from_uint(
-                    right.to_scalar().to_target_usize(self)?,
-                    self.machine.layouts.usize,
+                    right.to_scalar().to_target_usize(this)?,
+                    this.machine.layouts.usize,
                 );
-                let (result, overflowing) = self.overflowing_binary_op(bin_op, &left, &right)?;
+                let (result, overflowing) = this.overflowing_binary_op(bin_op, &left, &right)?;
                 // Construct a new pointer with the provenance of `ptr` (the LHS).
                 let result_ptr = Pointer::new(
                     ptr.provenance,
-                    Size::from_bytes(result.to_scalar().to_target_usize(self)?),
+                    Size::from_bytes(result.to_scalar().to_target_usize(this)?),
                 );
                 (
-                    ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout),
+                    ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, this), left.layout),
                     overflowing,
                 )
             }
 
-            _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
+            _ => span_bug!(this.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
         })
     }
+
+    fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 {
+        /// Make the given NaN a signaling NaN.
+        /// Returns `None` if this would not result in a NaN.
+        fn make_signaling<F: Float>(f: F) -> Option<F> {
+            // The quiet/signaling bit is the leftmost bit in the mantissa.
+            // That's position `PRECISION-1`, since `PRECISION` includes the fixed leading 1 bit,
+            // and then we subtract 1 more since this is 0-indexed.
+            let quiet_bit_mask = 1 << (F::PRECISION - 2);
+            // Unset the bit. Double-check that this wasn't the last bit set in the payload.
+            // (which would turn the NaN into an infinity).
+            let f = F::from_bits(f.to_bits() & !quiet_bit_mask);
+            if f.is_nan() { Some(f) } else { None }
+        }
+
+        let this = self.eval_context_ref();
+        let mut rand = this.machine.rng.borrow_mut();
+        // Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation.
+        // On some targets there are more possibilities; for now we just generate those options that
+        // are possible everywhere.
+        let preferred_nan = F2::qnan(Some(0));
+        let nans = iter::once(preferred_nan)
+            .chain(inputs.iter().filter(|f| f.is_nan()).map(|&f| {
+                // Regular apfloat cast is quieting.
+                f.convert(&mut false).value
+            }))
+            .chain(inputs.iter().filter(|f| f.is_signaling()).filter_map(|&f| {
+                let f: F2 = f.convert(&mut false).value;
+                // We have to de-quiet this again for unchanged propagation.
+                make_signaling(f)
+            }));
+        // Pick one of the NaNs.
+        let nan = nans.choose(&mut *rand).unwrap();
+        // Non-deterministically flip the sign.
+        if rand.gen() {
+            // This will properly flip even for NaN.
+            -nan
+        } else {
+            nan
+        }
+    }
 }
diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs
new file mode 100644
index 00000000000..9b0a40c41b9
--- /dev/null
+++ b/src/tools/miri/tests/pass/float_nan.rs
@@ -0,0 +1,411 @@
+use std::collections::HashSet;
+use std::fmt;
+use std::hash::Hash;
+use std::hint::black_box;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum Sign {
+    Neg = 1,
+    Pos = 0,
+}
+use Sign::*;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum NaNKind {
+    Quiet = 1,
+    Signaling = 0,
+}
+use NaNKind::*;
+
+#[track_caller]
+fn check_all_outcomes<T: Eq + Hash + fmt::Display>(expected: HashSet<T>, generate: impl Fn() -> T) {
+    let mut seen = HashSet::new();
+    // Let's give it 8x as many tries as we are expecting values.
+    let tries = expected.len() * 8;
+    for _ in 0..tries {
+        let val = generate();
+        assert!(expected.contains(&val), "got an unexpected value: {val}");
+        seen.insert(val);
+    }
+    // Let's see if we saw them all.
+    for val in expected {
+        if !seen.contains(&val) {
+            panic!("did not get value that should be possible: {val}");
+        }
+    }
+}
+
+// -- f32 support
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+struct F32(u32);
+
+impl From<f32> for F32 {
+    fn from(x: f32) -> Self {
+        F32(x.to_bits())
+    }
+}
+
+/// Returns a value that is `ones` many 1-bits.
+fn u32_ones(ones: u32) -> u32 {
+    assert!(ones <= 32);
+    if ones == 0 {
+        // `>>` by 32 doesn't actually shift. So inconsistent :(
+        return 0;
+    }
+    u32::MAX >> (32 - ones)
+}
+
+const F32_SIGN_BIT: u32 = 32 - 1; // position of the sign bit
+const F32_EXP: u32 = 8; // 8 bits of exponent
+const F32_MANTISSA: u32 = F32_SIGN_BIT - F32_EXP;
+const F32_NAN_PAYLOAD: u32 = F32_MANTISSA - 1;
+
+impl fmt::Display for F32 {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // Alaways show raw bits.
+        write!(f, "0x{:08x} ", self.0)?;
+        // Also show nice version.
+        let val = self.0;
+        let sign = val >> F32_SIGN_BIT;
+        let val = val & u32_ones(F32_SIGN_BIT); // mask away sign
+        let exp = val >> F32_MANTISSA;
+        let mantissa = val & u32_ones(F32_MANTISSA);
+        if exp == u32_ones(F32_EXP) {
+            // A NaN! Special printing.
+            let sign = if sign != 0 { Neg } else { Pos };
+            let quiet = if (mantissa >> F32_NAN_PAYLOAD) != 0 { Quiet } else { Signaling };
+            let payload = mantissa & u32_ones(F32_NAN_PAYLOAD);
+            write!(f, "(NaN: {:?}, {:?}, payload = {:#x})", sign, quiet, payload)
+        } else {
+            // Normal float value.
+            write!(f, "({})", f32::from_bits(self.0))
+        }
+    }
+}
+
+impl F32 {
+    fn nan(sign: Sign, kind: NaNKind, payload: u32) -> Self {
+        // Either the quiet bit must be set of the payload must be non-0;
+        // otherwise this is not a NaN but an infinity.
+        assert!(kind == Quiet || payload != 0);
+        // Payload must fit in 22 bits.
+        assert!(payload < (1 << F32_NAN_PAYLOAD));
+        // Concatenate the bits (with a 22bit payload).
+        // Pattern: [negative] ++ [1]^8 ++ [quiet] ++ [payload]
+        let val = ((sign as u32) << F32_SIGN_BIT)
+            | (u32_ones(F32_EXP) << F32_MANTISSA)
+            | ((kind as u32) << F32_NAN_PAYLOAD)
+            | payload;
+        // Sanity check.
+        assert!(f32::from_bits(val).is_nan());
+        // Done!
+        F32(val)
+    }
+
+    fn as_f32(self) -> f32 {
+        black_box(f32::from_bits(self.0))
+    }
+}
+
+// -- f64 support
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+struct F64(u64);
+
+impl From<f64> for F64 {
+    fn from(x: f64) -> Self {
+        F64(x.to_bits())
+    }
+}
+
+/// Returns a value that is `ones` many 1-bits.
+fn u64_ones(ones: u32) -> u64 {
+    assert!(ones <= 64);
+    if ones == 0 {
+        // `>>` by 32 doesn't actually shift. So inconsistent :(
+        return 0;
+    }
+    u64::MAX >> (64 - ones)
+}
+
+const F64_SIGN_BIT: u32 = 64 - 1; // position of the sign bit
+const F64_EXP: u32 = 11; // 11 bits of exponent
+const F64_MANTISSA: u32 = F64_SIGN_BIT - F64_EXP;
+const F64_NAN_PAYLOAD: u32 = F64_MANTISSA - 1;
+
+impl fmt::Display for F64 {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // Alaways show raw bits.
+        write!(f, "0x{:08x} ", self.0)?;
+        // Also show nice version.
+        let val = self.0;
+        let sign = val >> F64_SIGN_BIT;
+        let val = val & u64_ones(F64_SIGN_BIT); // mask away sign
+        let exp = val >> F64_MANTISSA;
+        let mantissa = val & u64_ones(F64_MANTISSA);
+        if exp == u64_ones(F64_EXP) {
+            // A NaN! Special printing.
+            let sign = if sign != 0 { Neg } else { Pos };
+            let quiet = if (mantissa >> F64_NAN_PAYLOAD) != 0 { Quiet } else { Signaling };
+            let payload = mantissa & u64_ones(F64_NAN_PAYLOAD);
+            write!(f, "(NaN: {:?}, {:?}, payload = {:#x})", sign, quiet, payload)
+        } else {
+            // Normal float value.
+            write!(f, "({})", f64::from_bits(self.0))
+        }
+    }
+}
+
+impl F64 {
+    fn nan(sign: Sign, kind: NaNKind, payload: u64) -> Self {
+        // Either the quiet bit must be set of the payload must be non-0;
+        // otherwise this is not a NaN but an infinity.
+        assert!(kind == Quiet || payload != 0);
+        // Payload must fit in 52 bits.
+        assert!(payload < (1 << F64_NAN_PAYLOAD));
+        // Concatenate the bits (with a 52bit payload).
+        // Pattern: [negative] ++ [1]^11 ++ [quiet] ++ [payload]
+        let val = ((sign as u64) << F64_SIGN_BIT)
+            | (u64_ones(F64_EXP) << F64_MANTISSA)
+            | ((kind as u64) << F64_NAN_PAYLOAD)
+            | payload;
+        // Sanity check.
+        assert!(f64::from_bits(val).is_nan());
+        // Done!
+        F64(val)
+    }
+
+    fn as_f64(self) -> f64 {
+        black_box(f64::from_bits(self.0))
+    }
+}
+
+// -- actual tests
+
+fn test_f32() {
+    // Freshly generated NaNs can have either sign.
+    check_all_outcomes(
+        HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
+        || F32::from(0.0 / black_box(0.0)),
+    );
+    // When there are NaN inputs, their payload can be propagated, with any sign.
+    let all1_payload = u32_ones(22);
+    let all1 = F32::nan(Pos, Quiet, all1_payload).as_f32();
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, all1_payload),
+            F32::nan(Neg, Quiet, all1_payload),
+        ]),
+        || F32::from(0.0 + all1),
+    );
+    // When there are two NaN inputs, the output can be either one, or the preferred NaN.
+    let just1 = F32::nan(Neg, Quiet, 1).as_f32();
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, 1),
+            F32::nan(Neg, Quiet, 1),
+            F32::nan(Pos, Quiet, all1_payload),
+            F32::nan(Neg, Quiet, all1_payload),
+        ]),
+        || F32::from(just1 - all1),
+    );
+    // When there are *signaling* NaN inputs, they might be quieted or not.
+    let all1_snan = F32::nan(Pos, Signaling, all1_payload).as_f32();
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, all1_payload),
+            F32::nan(Neg, Quiet, all1_payload),
+            F32::nan(Pos, Signaling, all1_payload),
+            F32::nan(Neg, Signaling, all1_payload),
+        ]),
+        || F32::from(0.0 * all1_snan),
+    );
+    // Mix signaling and non-signaling NaN.
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, 1),
+            F32::nan(Neg, Quiet, 1),
+            F32::nan(Pos, Quiet, all1_payload),
+            F32::nan(Neg, Quiet, all1_payload),
+            F32::nan(Pos, Signaling, all1_payload),
+            F32::nan(Neg, Signaling, all1_payload),
+        ]),
+        || F32::from(just1 % all1_snan),
+    );
+
+    // Unary `-` must preserve payloads exactly.
+    check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Quiet, all1_payload)]), || {
+        F32::from(-all1)
+    });
+    check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Signaling, all1_payload)]), || {
+        F32::from(-all1_snan)
+    });
+}
+
+fn test_f64() {
+    // Freshly generated NaNs can have either sign.
+    check_all_outcomes(
+        HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
+        || F64::from(0.0 / black_box(0.0)),
+    );
+    // When there are NaN inputs, their payload can be propagated, with any sign.
+    let all1_payload = u64_ones(51);
+    let all1 = F64::nan(Pos, Quiet, all1_payload).as_f64();
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, all1_payload),
+            F64::nan(Neg, Quiet, all1_payload),
+        ]),
+        || F64::from(0.0 + all1),
+    );
+    // When there are two NaN inputs, the output can be either one, or the preferred NaN.
+    let just1 = F64::nan(Neg, Quiet, 1).as_f64();
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, 1),
+            F64::nan(Neg, Quiet, 1),
+            F64::nan(Pos, Quiet, all1_payload),
+            F64::nan(Neg, Quiet, all1_payload),
+        ]),
+        || F64::from(just1 - all1),
+    );
+    // When there are *signaling* NaN inputs, they might be quieted or not.
+    let all1_snan = F64::nan(Pos, Signaling, all1_payload).as_f64();
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, all1_payload),
+            F64::nan(Neg, Quiet, all1_payload),
+            F64::nan(Pos, Signaling, all1_payload),
+            F64::nan(Neg, Signaling, all1_payload),
+        ]),
+        || F64::from(0.0 * all1_snan),
+    );
+    // Mix signaling and non-signaling NaN.
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, 1),
+            F64::nan(Neg, Quiet, 1),
+            F64::nan(Pos, Quiet, all1_payload),
+            F64::nan(Neg, Quiet, all1_payload),
+            F64::nan(Pos, Signaling, all1_payload),
+            F64::nan(Neg, Signaling, all1_payload),
+        ]),
+        || F64::from(just1 % all1_snan),
+    );
+}
+
+fn test_casts() {
+    let all1_payload_32 = u32_ones(22);
+    let all1_payload_64 = u64_ones(51);
+    let left1_payload_64 = (all1_payload_32 as u64) << (51 - 22);
+
+    // 64-to-32
+    check_all_outcomes(
+        HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
+        || F32::from(F64::nan(Pos, Quiet, 0).as_f64() as f32),
+    );
+    // The preferred payload is always a possibility.
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, all1_payload_32),
+            F32::nan(Neg, Quiet, all1_payload_32),
+        ]),
+        || F32::from(F64::nan(Pos, Quiet, all1_payload_64).as_f64() as f32),
+    );
+    // If the input is signaling, then the output *may* also be signaling.
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, all1_payload_32),
+            F32::nan(Neg, Quiet, all1_payload_32),
+            F32::nan(Pos, Signaling, all1_payload_32),
+            F32::nan(Neg, Signaling, all1_payload_32),
+        ]),
+        || F32::from(F64::nan(Pos, Signaling, all1_payload_64).as_f64() as f32),
+    );
+    // Check that the low bits are gone (not the high bits).
+    check_all_outcomes(
+        HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
+        || F32::from(F64::nan(Pos, Quiet, 1).as_f64() as f32),
+    );
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, 1),
+            F32::nan(Neg, Quiet, 1),
+        ]),
+        || F32::from(F64::nan(Pos, Quiet, 1 << (51 - 22)).as_f64() as f32),
+    );
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            // The `1` payload becomes `0`, and the `0` payload cannot be signaling,
+            // so these are the only options.
+        ]),
+        || F32::from(F64::nan(Pos, Signaling, 1).as_f64() as f32),
+    );
+
+    // 32-to-64
+    check_all_outcomes(
+        HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
+        || F64::from(F32::nan(Pos, Quiet, 0).as_f32() as f64),
+    );
+    // The preferred payload is always a possibility.
+    // Also checks that 0s are added on the right.
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, left1_payload_64),
+            F64::nan(Neg, Quiet, left1_payload_64),
+        ]),
+        || F64::from(F32::nan(Pos, Quiet, all1_payload_32).as_f32() as f64),
+    );
+    // If the input is signaling, then the output *may* also be signaling.
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, left1_payload_64),
+            F64::nan(Neg, Quiet, left1_payload_64),
+            F64::nan(Pos, Signaling, left1_payload_64),
+            F64::nan(Neg, Signaling, left1_payload_64),
+        ]),
+        || F64::from(F32::nan(Pos, Signaling, all1_payload_32).as_f32() as f64),
+    );
+}
+
+fn main() {
+    // Check our constants against std, just to be sure.
+    // We add 1 since our numbers are the number of bits stored
+    // to represent the value, and std has the precision of the value,
+    // which is one more due to the implicit leading 1.
+    assert_eq!(F32_MANTISSA + 1, f32::MANTISSA_DIGITS);
+    assert_eq!(F64_MANTISSA + 1, f64::MANTISSA_DIGITS);
+
+    test_f32();
+    test_f64();
+    test_casts();
+}
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index f1c3dd6aa9b..c212e8aafe1 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -23,3 +23,4 @@ glob = "0.3"
 tempfile = "3.5"
 derive_builder = "0.12"
 clap = { version = "4", features = ["derive"] }
+tabled = "0.13"
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index 978e2dfa4e8..03a1912f5ce 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -13,10 +13,11 @@ use crate::exec::{cmd, Bootstrap};
 use crate::tests::run_tests;
 use crate::timer::Timer;
 use crate::training::{gather_llvm_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles};
+use crate::utils::artifact_size::print_binary_sizes;
 use crate::utils::io::{copy_directory, move_directory, reset_directory};
 use crate::utils::{
-    clear_llvm_files, format_env_variables, print_binary_sizes, print_free_disk_space,
-    retry_action, with_log_group,
+    clear_llvm_files, format_env_variables, print_free_disk_space, retry_action, with_log_group,
+    write_timer_to_summary,
 };
 
 mod bolt;
@@ -359,6 +360,10 @@ fn main() -> anyhow::Result<()> {
     let result = execute_pipeline(&env, &mut timer, build_args);
     log::info!("Timer results\n{}", timer.format_stats());
 
+    if let Ok(summary_path) = std::env::var("GITHUB_STEP_SUMMARY") {
+        write_timer_to_summary(&summary_path, &timer)?;
+    }
+
     print_free_disk_space()?;
     result.context("Optimized build pipeline has failed")?;
     print_binary_sizes(&env)?;
diff --git a/src/tools/opt-dist/src/utils/artifact_size.rs b/src/tools/opt-dist/src/utils/artifact_size.rs
new file mode 100644
index 00000000000..4dc8952b60a
--- /dev/null
+++ b/src/tools/opt-dist/src/utils/artifact_size.rs
@@ -0,0 +1,61 @@
+use std::io::Write;
+
+use tabled::builder::Builder;
+use tabled::settings::object::Columns;
+use tabled::settings::style::{BorderChar, Offset};
+use tabled::settings::{Modify, Style};
+
+use crate::environment::Environment;
+use crate::utils::io::get_files_from_dir;
+
+pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> {
+    use humansize::format_size;
+    use humansize::BINARY;
+    use std::fmt::Write;
+
+    let root = env.build_artifacts().join("stage2");
+
+    let mut files = get_files_from_dir(&root.join("bin"), None)?;
+    files.extend(get_files_from_dir(&root.join("lib"), Some(".so"))?);
+    files.sort_unstable();
+
+    let items: Vec<_> = files
+        .into_iter()
+        .map(|file| {
+            let size = std::fs::metadata(file.as_std_path()).map(|m| m.len()).unwrap_or(0);
+            let size_formatted = format_size(size, BINARY);
+            let name = file.file_name().unwrap().to_string();
+            (name, size_formatted)
+        })
+        .collect();
+
+    // Write to log
+    let mut output = String::new();
+    for (name, size_formatted) in items.iter() {
+        let name = format!("{}:", name);
+        writeln!(output, "{name:<50}{size_formatted:>10}")?;
+    }
+    log::info!("Rustc artifact size\n{output}");
+
+    // Write to GitHub summary
+    if let Ok(summary_path) = std::env::var("GITHUB_STEP_SUMMARY") {
+        let mut builder = Builder::default();
+        for (name, size_formatted) in items {
+            builder.push_record(vec![name, size_formatted]);
+        }
+
+        builder.set_header(vec!["Artifact", "Size"]);
+        let mut table = builder.build();
+
+        let mut file = std::fs::File::options().append(true).create(true).open(summary_path)?;
+        writeln!(
+            file,
+            "# Artifact size\n{}\n",
+            table.with(Style::markdown()).with(
+                Modify::new(Columns::single(1)).with(BorderChar::horizontal(':', Offset::End(0))),
+            )
+        )?;
+    }
+
+    Ok(())
+}
diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs
index 6fc96592a88..ca1292dd5b8 100644
--- a/src/tools/opt-dist/src/utils/mod.rs
+++ b/src/tools/opt-dist/src/utils/mod.rs
@@ -1,10 +1,13 @@
-pub mod io;
+use sysinfo::{DiskExt, RefreshKind, System, SystemExt};
 
 use crate::environment::Environment;
-use crate::utils::io::{delete_directory, get_files_from_dir};
-use humansize::{format_size, BINARY};
+use crate::timer::Timer;
+use crate::utils::io::delete_directory;
+use humansize::BINARY;
 use std::time::Duration;
-use sysinfo::{DiskExt, RefreshKind, System, SystemExt};
+
+pub mod artifact_size;
+pub mod io;
 
 pub fn format_env_variables() -> String {
     let vars = std::env::vars().map(|(key, value)| format!("{key}={value}")).collect::<Vec<_>>();
@@ -26,28 +29,6 @@ pub fn print_free_disk_space() -> anyhow::Result<()> {
     Ok(())
 }
 
-pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> {
-    use std::fmt::Write;
-
-    let root = env.build_artifacts().join("stage2");
-
-    let mut files = get_files_from_dir(&root.join("bin"), None)?;
-    files.extend(get_files_from_dir(&root.join("lib"), Some(".so"))?);
-    files.sort_unstable();
-
-    let mut output = String::new();
-    for file in files {
-        let size = std::fs::metadata(file.as_std_path())?.len();
-        let size_formatted = format_size(size, BINARY);
-        let name = format!("{}:", file.file_name().unwrap());
-        writeln!(output, "{name:<50}{size_formatted:>10}")?;
-    }
-
-    log::info!("Rustc artifact size\n{output}");
-
-    Ok(())
-}
-
 pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> {
     // Bootstrap currently doesn't support rebuilding LLVM when PGO options
     // change (or any other llvm-related options); so just clear out the relevant
@@ -58,6 +39,24 @@ pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> {
     Ok(())
 }
 
+/// Write the formatted statistics of the timer to a Github Actions summary.
+pub fn write_timer_to_summary(path: &str, timer: &Timer) -> anyhow::Result<()> {
+    use std::io::Write;
+
+    let mut file = std::fs::File::options().append(true).create(true).open(path)?;
+    writeln!(
+        file,
+        r#"# Step durations
+
+```
+{}
+```
+"#,
+        timer.format_stats()
+    )?;
+    Ok(())
+}
+
 /// Wraps all output produced within the `func` closure in a CI output group, if we're running in
 /// CI.
 pub fn with_log_group<F: FnOnce() -> R, R>(group: &str, func: F) -> R {
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 49210967c44..f89faacc2d1 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -326,7 +326,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "ahash",
     "anyhow",
     "arbitrary",
-    "autocfg",
     "bitflags",
     "bumpalo",
     "cfg-if",
diff --git a/tests/codegen/debug-fndef-size.rs b/tests/codegen/debug-fndef-size.rs
new file mode 100644
index 00000000000..80eb35fa32a
--- /dev/null
+++ b/tests/codegen/debug-fndef-size.rs
@@ -0,0 +1,18 @@
+// Verify that `i32::cmp` FnDef type is declared with size 0 and align 1 in LLVM debuginfo.
+// compile-flags: -O -g -Cno-prepopulate-passes
+// ignore-msvc the types are mangled differently
+
+use std::cmp::Ordering;
+
+fn foo<F: FnOnce(&i32, &i32) -> Ordering>(v1: i32, v2: i32, compare: F) -> Ordering {
+    compare(&v1, &v2)
+}
+
+pub fn main() {
+    foo(0, 1, i32::cmp);
+}
+
+// CHECK: %compare.dbg.spill = alloca {}, align 1
+// CHECK: call void @llvm.dbg.declare(metadata ptr %compare.dbg.spill, metadata ![[VAR:.*]], metadata !DIExpression()), !dbg !{{.*}}
+// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 1, dwarfAddressSpace: {{.*}})
+// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 1)
diff --git a/tests/incremental/hashes/for_loops.rs b/tests/incremental/hashes/for_loops.rs
index 193e792c843..98c762e4097 100644
--- a/tests/incremental/hashes/for_loops.rs
+++ b/tests/incremental/hashes/for_loops.rs
@@ -28,9 +28,9 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_loop_body() {
     let mut _x = 0;
@@ -180,7 +180,7 @@ pub fn add_loop_label_to_break() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_loop_label_to_break() {
     let mut _x = 0;
diff --git a/tests/incremental/hashes/loop_expressions.rs b/tests/incremental/hashes/loop_expressions.rs
index 87b86479d07..13e37bd59f8 100644
--- a/tests/incremental/hashes/loop_expressions.rs
+++ b/tests/incremental/hashes/loop_expressions.rs
@@ -28,9 +28,9 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/tests/incremental/hashes/while_loops.rs b/tests/incremental/hashes/while_loops.rs
index c1cc0b62bc2..077d76fdd43 100644
--- a/tests/incremental/hashes/while_loops.rs
+++ b/tests/incremental/hashes/while_loops.rs
@@ -28,9 +28,9 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_loop_body() {
     let mut _x = 0;
@@ -53,9 +53,9 @@ pub fn change_loop_condition() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_loop_condition() {
     let mut _x = 0;
@@ -211,7 +211,7 @@ pub fn change_continue_label() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_continue_label() {
     let mut _x = 0;
diff --git a/tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff b/tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff
new file mode 100644
index 00000000000..4d56a8b25d3
--- /dev/null
+++ b/tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff
@@ -0,0 +1,21 @@
+- // MIR for `multiple_edges` before CopyProp
++ // MIR for `multiple_edges` after CopyProp
+  
+  fn multiple_edges(_1: bool) -> u8 {
+      let mut _0: u8;
+      let mut _2: u8;
+  
+      bb0: {
+          switchInt(_1) -> [1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          _2 = dummy(const 13_u8) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          _0 = _2;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff b/tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff
new file mode 100644
index 00000000000..b5d56909b0d
--- /dev/null
+++ b/tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff
@@ -0,0 +1,24 @@
+- // MIR for `nrvo` before CopyProp
++ // MIR for `nrvo` after CopyProp
+  
+  fn nrvo() -> u8 {
+      let mut _0: u8;
+      let _1: u8;
+      scope 1 {
+-         debug y => _1;
++         debug y => _0;
+      }
+  
+      bb0: {
+-         StorageLive(_1);
+-         _1 = dummy(const 5_u8) -> [return: bb1, unwind continue];
++         _0 = dummy(const 5_u8) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _0 = _1;
+-         StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/calls.rs b/tests/mir-opt/copy-prop/calls.rs
new file mode 100644
index 00000000000..c1f86f1f412
--- /dev/null
+++ b/tests/mir-opt/copy-prop/calls.rs
@@ -0,0 +1,43 @@
+// Check that CopyProp does propagate return values of call terminators.
+// unit-test: CopyProp
+// needs-unwind
+
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+#[inline(never)]
+fn dummy(x: u8) -> u8 {
+    x
+}
+
+// EMIT_MIR calls.nrvo.CopyProp.diff
+fn nrvo() -> u8 {
+    let y = dummy(5); // this should get NRVO
+    y
+}
+
+// EMIT_MIR calls.multiple_edges.CopyProp.diff
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn multiple_edges(t: bool) -> u8 {
+    mir! {
+        let x: u8;
+        {
+            match t { true => bbt, _ => ret }
+        }
+        bbt = {
+            Call(x = dummy(13), ret)
+        }
+        ret = {
+            // `x` is not assigned on the `bb0 -> ret` edge,
+            // so should not be marked as SSA for merging with `_0`.
+            RET = x;
+            Return()
+        }
+    }
+}
+
+fn main() {
+    // Make sure the function actually gets instantiated.
+    nrvo();
+    multiple_edges(false);
+}
diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
new file mode 100644
index 00000000000..cf73358dc52
--- /dev/null
+++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
@@ -0,0 +1,29 @@
+- // MIR for `cycle` before DeadStoreElimination
++ // MIR for `cycle` after DeadStoreElimination
+  
+  fn cycle(_1: i32, _2: i32, _3: i32) -> () {
+      let mut _0: ();
+      let mut _4: bool;
+-     let mut _5: i32;
+  
+      bb0: {
+          _4 = cond() -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          switchInt(_4) -> [1: bb2, otherwise: bb3];
+      }
+  
+      bb2: {
+-         _5 = _3;
+-         _3 = _2;
+-         _2 = _1;
+-         _1 = _5;
+          _4 = cond() -> [return: bb1, unwind continue];
+      }
+  
+      bb3: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-abort.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-abort.diff
deleted file mode 100644
index 6221d478041..00000000000
--- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-abort.diff
+++ /dev/null
@@ -1,73 +0,0 @@
-- // MIR for `cycle` before DeadStoreElimination
-+ // MIR for `cycle` after DeadStoreElimination
-  
-  fn cycle(_1: i32, _2: i32, _3: i32) -> () {
-      debug x => _1;
-      debug y => _2;
-      debug z => _3;
-      let mut _0: ();
--     let mut _4: ();
--     let mut _5: bool;
--     let _6: i32;
--     let mut _7: i32;
--     let mut _8: i32;
--     let mut _9: i32;
--     let mut _10: !;
--     let _11: ();
--     let mut _12: !;
-+     let mut _4: bool;
-+     let _5: i32;
-      scope 1 {
--         debug temp => _6;
-+         debug temp => _5;
-      }
-  
-      bb0: {
-          goto -> bb1;
-      }
-  
-      bb1: {
--         StorageLive(_5);
--         _5 = cond() -> [return: bb2, unwind unreachable];
-+         StorageLive(_4);
-+         _4 = cond() -> [return: bb2, unwind unreachable];
-      }
-  
-      bb2: {
--         switchInt(move _5) -> [0: bb4, otherwise: bb3];
-+         switchInt(move _4) -> [0: bb4, otherwise: bb3];
-      }
-  
-      bb3: {
--         StorageLive(_6);
--         _6 = _3;
--         StorageLive(_7);
--         _7 = _2;
--         _3 = move _7;
--         StorageDead(_7);
--         StorageLive(_8);
--         _8 = _1;
--         _2 = move _8;
--         StorageDead(_8);
--         StorageLive(_9);
--         _9 = _6;
--         _1 = move _9;
--         StorageDead(_9);
--         _4 = const ();
--         StorageDead(_6);
-+         StorageLive(_5);
-          StorageDead(_5);
-+         StorageDead(_4);
-          goto -> bb1;
-      }
-  
-      bb4: {
--         StorageLive(_11);
-          _0 = const ();
--         StorageDead(_11);
--         StorageDead(_5);
-+         StorageDead(_4);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff
deleted file mode 100644
index 4b922e05e10..00000000000
--- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff
+++ /dev/null
@@ -1,73 +0,0 @@
-- // MIR for `cycle` before DeadStoreElimination
-+ // MIR for `cycle` after DeadStoreElimination
-  
-  fn cycle(_1: i32, _2: i32, _3: i32) -> () {
-      debug x => _1;
-      debug y => _2;
-      debug z => _3;
-      let mut _0: ();
--     let mut _4: ();
--     let mut _5: bool;
--     let _6: i32;
--     let mut _7: i32;
--     let mut _8: i32;
--     let mut _9: i32;
--     let mut _10: !;
--     let _11: ();
--     let mut _12: !;
-+     let mut _4: bool;
-+     let _5: i32;
-      scope 1 {
--         debug temp => _6;
-+         debug temp => _5;
-      }
-  
-      bb0: {
-          goto -> bb1;
-      }
-  
-      bb1: {
--         StorageLive(_5);
--         _5 = cond() -> [return: bb2, unwind continue];
-+         StorageLive(_4);
-+         _4 = cond() -> [return: bb2, unwind continue];
-      }
-  
-      bb2: {
--         switchInt(move _5) -> [0: bb4, otherwise: bb3];
-+         switchInt(move _4) -> [0: bb4, otherwise: bb3];
-      }
-  
-      bb3: {
--         StorageLive(_6);
--         _6 = _3;
--         StorageLive(_7);
--         _7 = _2;
--         _3 = move _7;
--         StorageDead(_7);
--         StorageLive(_8);
--         _8 = _1;
--         _2 = move _8;
--         StorageDead(_8);
--         StorageLive(_9);
--         _9 = _6;
--         _1 = move _9;
--         StorageDead(_9);
--         _4 = const ();
--         StorageDead(_6);
-+         StorageLive(_5);
-          StorageDead(_5);
-+         StorageDead(_4);
-          goto -> bb1;
-      }
-  
-      bb4: {
--         StorageLive(_11);
-          _0 = const ();
--         StorageDead(_11);
--         StorageDead(_5);
-+         StorageDead(_4);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/dead-store-elimination/cycle.rs b/tests/mir-opt/dead-store-elimination/cycle.rs
index cd34fe96e8c..e3def2f65da 100644
--- a/tests/mir-opt/dead-store-elimination/cycle.rs
+++ b/tests/mir-opt/dead-store-elimination/cycle.rs
@@ -1,21 +1,40 @@
-// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// This example is interesting because the non-transitive version of `MaybeLiveLocals` would
+// report that *all* of these stores are live.
+//
+// needs-unwind
 // unit-test: DeadStoreElimination
 
+#![feature(core_intrinsics, custom_mir)]
+use std::intrinsics::mir::*;
+
 #[inline(never)]
 fn cond() -> bool {
     false
 }
 
 // EMIT_MIR cycle.cycle.DeadStoreElimination.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
 fn cycle(mut x: i32, mut y: i32, mut z: i32) {
-    // This example is interesting because the non-transitive version of `MaybeLiveLocals` would
-    // report that *all* of these stores are live.
-    while cond() {
-        let temp = z;
-        z = y;
-        y = x;
-        x = temp;
-    }
+    // We use custom MIR to avoid generating debuginfo, that would force to preserve writes.
+    mir!(
+        let condition: bool;
+        {
+            Call(condition = cond(), bb1)
+        }
+        bb1 = {
+            match condition { true => bb2, _ => ret }
+        }
+        bb2 = {
+            let temp = z;
+            z = y;
+            y = x;
+            x = temp;
+            Call(condition = cond(), bb1)
+        }
+        ret = {
+            Return()
+        }
+    )
 }
 
 fn main() {
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir
index a3ec0901075..eb160fc194a 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir
@@ -7,15 +7,16 @@ fn f(_1: usize) -> usize {
     let mut _3: usize;
     let mut _4: usize;
     scope 1 {
-        debug b => _1;
+        debug b => _3;
     }
 
     bb0: {
         nop;
+        _3 = _1;
+        _1 = const 5_usize;
         nop;
         nop;
-        nop;
-        nop;
+        _1 = move _3;
         nop;
         nop;
         nop;
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
index 185feb4b418..9147de2ec47 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
@@ -7,15 +7,16 @@ fn f(_1: usize) -> usize {
     let mut _3: usize;
     let mut _4: usize;
     scope 1 {
-        debug b => _1;
+        debug b => _3;
     }
 
     bb0: {
         nop;
+        _3 = _1;
+        _1 = const 5_usize;
         nop;
         nop;
-        nop;
-        nop;
+        _1 = move _3;
         nop;
         nop;
         nop;
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
index 459a9c442b3..d5e58265dcc 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
@@ -22,8 +22,10 @@
       }
   
       bb1: {
+          _1 = Un { us: move _2 };
           StorageDead(_2);
           StorageLive(_3);
+          _3 = (_1.0: u32);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
index d2eef90582d..5eaaeba135b 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
@@ -22,8 +22,10 @@
       }
   
       bb1: {
+          _1 = Un { us: move _2 };
           StorageDead(_2);
           StorageLive(_3);
+          _3 = (_1.0: u32);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff
index 7d5553b2f37..da45ebcb4d8 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff
@@ -8,11 +8,11 @@
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
 +         debug f => _2;
 +         let mut _3: &fn() -> ! {sleep};
-+         let mut _4: !;
++         let _4: !;
 +         let mut _5: &fn() -> ! {sleep};
-+         let mut _6: !;
 +         scope 2 {
 +             debug a => _4;
++             let _6: !;
 +             scope 3 {
 +                 debug b => _6;
 +             }
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
index 9f8c5806c90..d65c65e5fd0 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
@@ -10,10 +10,10 @@
 +         let mut _3: &fn() -> ! {sleep};
 +         let _4: !;
 +         let mut _5: &fn() -> ! {sleep};
-+         let mut _6: !;
 +         let mut _7: !;
 +         scope 2 {
 +             debug a => _4;
++             let _6: !;
 +             scope 3 {
 +                 debug b => _6;
 +             }
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff b/tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff
index ce490e894f0..3748d148380 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff
@@ -33,6 +33,7 @@
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
+          _4 = const 0_u32;
           StorageLive(_15);
           StorageLive(_14);
           _14 = Shr(_1, const 0_i32);
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
index 254557b9947..9dab4233c56 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
@@ -33,6 +33,7 @@
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
+          _4 = const 0_u32;
           StorageLive(_15);
           StorageLive(_14);
           _14 = Shr(_1, const 0_i32);
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir
index 55ccf6a8b45..5d25c655700 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir
@@ -3,60 +3,61 @@
 fn num_to_digit(_1: char) -> u32 {
     debug num => _1;
     let mut _0: u32;
-    let mut _4: std::option::Option<u32>;
+    let mut _5: std::option::Option<u32>;
     scope 1 (inlined char::methods::<impl char>::is_digit) {
         debug self => _1;
         debug radix => const 8_u32;
         let _2: std::option::Option<u32>;
-        let mut _7: &std::option::Option<u32>;
+        let mut _3: &std::option::Option<u32>;
         scope 2 (inlined Option::<u32>::is_some) {
-            debug self => _7;
-            let mut _3: isize;
+            debug self => _3;
+            let mut _4: isize;
         }
     }
     scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
-        debug self => _4;
-        let mut _5: isize;
-        let mut _6: !;
+        debug self => _5;
+        let mut _6: isize;
+        let mut _7: !;
         scope 4 {
             debug val => _0;
         }
     }
 
     bb0: {
-        StorageLive(_7);
+        StorageLive(_3);
         StorageLive(_2);
         _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> [return: bb1, unwind unreachable];
     }
 
     bb1: {
-        StorageLive(_3);
-        _3 = discriminant(_2);
-        StorageDead(_7);
+        _3 = &_2;
+        StorageLive(_4);
+        _4 = discriminant(_2);
+        StorageDead(_3);
         StorageDead(_2);
-        switchInt(move _3) -> [1: bb2, otherwise: bb7];
+        switchInt(move _4) -> [1: bb2, otherwise: bb7];
     }
 
     bb2: {
-        StorageDead(_3);
-        StorageLive(_4);
-        _4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable];
+        StorageDead(_4);
+        StorageLive(_5);
+        _5 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        StorageLive(_5);
-        _5 = discriminant(_4);
-        switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
+        StorageLive(_6);
+        _6 = discriminant(_5);
+        switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6];
     }
 
     bb4: {
-        _6 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind unreachable;
+        _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind unreachable;
     }
 
     bb5: {
-        _0 = move ((_4 as Some).0: u32);
+        _0 = move ((_5 as Some).0: u32);
+        StorageDead(_6);
         StorageDead(_5);
-        StorageDead(_4);
         goto -> bb8;
     }
 
@@ -65,7 +66,7 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb7: {
-        StorageDead(_3);
+        StorageDead(_4);
         _0 = const 0_u32;
         goto -> bb8;
     }
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir
index cb70a83e7f8..4677c0108e3 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir
@@ -3,60 +3,61 @@
 fn num_to_digit(_1: char) -> u32 {
     debug num => _1;
     let mut _0: u32;
-    let mut _4: std::option::Option<u32>;
+    let mut _5: std::option::Option<u32>;
     scope 1 (inlined char::methods::<impl char>::is_digit) {
         debug self => _1;
         debug radix => const 8_u32;
         let _2: std::option::Option<u32>;
-        let mut _7: &std::option::Option<u32>;
+        let mut _3: &std::option::Option<u32>;
         scope 2 (inlined Option::<u32>::is_some) {
-            debug self => _7;
-            let mut _3: isize;
+            debug self => _3;
+            let mut _4: isize;
         }
     }
     scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
-        debug self => _4;
-        let mut _5: isize;
-        let mut _6: !;
+        debug self => _5;
+        let mut _6: isize;
+        let mut _7: !;
         scope 4 {
             debug val => _0;
         }
     }
 
     bb0: {
-        StorageLive(_7);
+        StorageLive(_3);
         StorageLive(_2);
         _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> [return: bb1, unwind continue];
     }
 
     bb1: {
-        StorageLive(_3);
-        _3 = discriminant(_2);
-        StorageDead(_7);
+        _3 = &_2;
+        StorageLive(_4);
+        _4 = discriminant(_2);
+        StorageDead(_3);
         StorageDead(_2);
-        switchInt(move _3) -> [1: bb2, otherwise: bb7];
+        switchInt(move _4) -> [1: bb2, otherwise: bb7];
     }
 
     bb2: {
-        StorageDead(_3);
-        StorageLive(_4);
-        _4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
+        StorageDead(_4);
+        StorageLive(_5);
+        _5 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
     }
 
     bb3: {
-        StorageLive(_5);
-        _5 = discriminant(_4);
-        switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
+        StorageLive(_6);
+        _6 = discriminant(_5);
+        switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6];
     }
 
     bb4: {
-        _6 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind continue;
+        _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind continue;
     }
 
     bb5: {
-        _0 = move ((_4 as Some).0: u32);
+        _0 = move ((_5 as Some).0: u32);
+        StorageDead(_6);
         StorageDead(_5);
-        StorageDead(_4);
         goto -> bb8;
     }
 
@@ -65,7 +66,7 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb7: {
-        StorageDead(_3);
+        StorageDead(_4);
         _0 = const 0_u32;
         goto -> bb8;
     }
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir
index e3c81061a46..cf7feef0051 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir
@@ -8,61 +8,62 @@ fn step_forward(_1: u32, _2: usize) -> u32 {
         debug start => _1;
         debug n => _2;
         let _3: std::option::Option<u32>;
-        let mut _6: bool;
-        let mut _7: u32;
-        let mut _8: &std::option::Option<u32>;
+        let mut _4: &std::option::Option<u32>;
+        let mut _7: bool;
+        let mut _8: u32;
         scope 2 {
         }
         scope 3 (inlined Option::<u32>::is_none) {
-            debug self => _8;
-            let mut _5: bool;
+            debug self => _4;
+            let mut _6: bool;
             scope 4 (inlined Option::<u32>::is_some) {
-                debug self => _8;
-                let mut _4: isize;
+                debug self => _4;
+                let mut _5: isize;
             }
         }
         scope 5 (inlined core::num::<impl u32>::wrapping_add) {
             debug self => _1;
-            debug rhs => _7;
+            debug rhs => _8;
         }
     }
 
     bb0: {
-        StorageLive(_6);
-        StorageLive(_8);
+        StorageLive(_7);
+        StorageLive(_4);
         StorageLive(_3);
         _3 = <u32 as Step>::forward_checked(_1, _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
+        _4 = &_3;
+        StorageLive(_6);
         StorageLive(_5);
-        StorageLive(_4);
-        _4 = discriminant(_3);
-        _5 = Eq(_4, const 1_isize);
-        StorageDead(_4);
-        _6 = Not(move _5);
+        _5 = discriminant(_3);
+        _6 = Eq(_5, const 1_isize);
         StorageDead(_5);
-        switchInt(move _6) -> [0: bb2, otherwise: bb3];
+        _7 = Not(move _6);
+        StorageDead(_6);
+        switchInt(move _7) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
         StorageDead(_3);
-        StorageDead(_8);
+        StorageDead(_4);
         goto -> bb4;
     }
 
     bb3: {
         StorageDead(_3);
-        StorageDead(_8);
+        StorageDead(_4);
         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const _, const 1_u32) -> [success: bb4, unwind continue];
     }
 
     bb4: {
-        StorageDead(_6);
-        StorageLive(_7);
-        _7 = _2 as u32 (IntToInt);
-        _0 = Add(_1, _7);
         StorageDead(_7);
+        StorageLive(_8);
+        _8 = _2 as u32 (IntToInt);
+        _0 = Add(_1, _8);
+        StorageDead(_8);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
index 4db829a5ec3..8dbb688999a 100644
--- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
@@ -6,19 +6,18 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     let mut _0: ();
     let mut _3: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
     let mut _4: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
-    let mut _5: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
+    let mut _5: &mut std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
     let mut _8: std::option::Option<U>;
     let mut _9: isize;
     let _11: ();
-    let mut _12: &mut std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
     scope 1 {
-        debug iter => _5;
+        debug iter => _4;
         let _10: U;
         scope 2 {
             debug x => _10;
         }
         scope 4 (inlined <FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>> as Iterator>::next) {
-            debug self => _12;
+            debug self => _5;
             let mut _6: &mut impl Iterator<Item = T>;
             let mut _7: &mut impl Fn(T) -> Option<U>;
         }
@@ -28,25 +27,22 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     }
 
     bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
         _3 = <impl Iterator<Item = T> as Iterator>::filter_map::<U, impl Fn(T) -> Option<U>>(move _1, move _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
+        StorageLive(_4);
         _4 = move _3;
-        StorageDead(_3);
-        StorageLive(_5);
-        _5 = move _4;
         goto -> bb2;
     }
 
     bb2: {
         StorageLive(_8);
+        _5 = &mut _4;
         StorageLive(_6);
-        _6 = &mut (_5.0: impl Iterator<Item = T>);
+        _6 = &mut (_4.0: impl Iterator<Item = T>);
         StorageLive(_7);
-        _7 = &mut (_5.1: impl Fn(T) -> Option<U>);
+        _7 = &mut (_4.1: impl Fn(T) -> Option<U>);
         _8 = <impl Iterator<Item = T> as Iterator>::find_map::<U, &mut impl Fn(T) -> Option<U>>(move _6, move _7) -> [return: bb3, unwind: bb9];
     }
 
@@ -59,11 +55,10 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
 
     bb4: {
         StorageDead(_8);
-        drop(_5) -> [return: bb5, unwind continue];
+        drop(_4) -> [return: bb5, unwind continue];
     }
 
     bb5: {
-        StorageDead(_5);
         StorageDead(_4);
         return;
     }
@@ -83,7 +78,7 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     }
 
     bb9 (cleanup): {
-        drop(_5) -> [return: bb10, unwind terminate(cleanup)];
+        drop(_4) -> [return: bb10, unwind terminate(cleanup)];
     }
 
     bb10 (cleanup): {
diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
index 0d79f2de10d..49f685cfacd 100644
--- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
@@ -6,35 +6,35 @@ fn int_range(_1: usize, _2: usize) -> () {
     let mut _0: ();
     let mut _3: std::ops::Range<usize>;
     let mut _4: std::ops::Range<usize>;
-    let mut _8: std::option::Option<usize>;
-    let mut _11: isize;
-    let _13: ();
-    let mut _14: &mut std::ops::Range<usize>;
+    let mut _5: &mut std::ops::Range<usize>;
+    let mut _11: std::option::Option<usize>;
+    let mut _14: isize;
+    let _16: ();
     scope 1 {
         debug iter => _4;
-        let _12: usize;
+        let _15: usize;
         scope 2 {
-            debug i => _12;
+            debug i => _15;
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
-            debug self => _14;
+            debug self => _5;
             scope 5 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) {
-                debug self => _14;
-                let mut _7: bool;
-                let _9: usize;
-                let mut _10: usize;
-                let mut _15: &usize;
-                let mut _16: &usize;
+                debug self => _5;
+                let mut _6: &usize;
+                let mut _7: &usize;
+                let mut _10: bool;
+                let _12: usize;
+                let mut _13: usize;
                 scope 6 {
-                    debug old => _9;
+                    debug old => _12;
                     scope 7 {
                     }
                 }
                 scope 8 (inlined cmp::impls::<impl PartialOrd for usize>::lt) {
-                    debug self => _15;
-                    debug other => _16;
-                    let mut _5: usize;
-                    let mut _6: usize;
+                    debug self => _6;
+                    debug other => _7;
+                    let mut _8: usize;
+                    let mut _9: usize;
                 }
             }
         }
@@ -51,63 +51,66 @@ fn int_range(_1: usize, _2: usize) -> () {
     }
 
     bb1: {
+        StorageLive(_11);
+        _5 = &mut _4;
+        StorageLive(_12);
+        StorageLive(_10);
+        StorageLive(_6);
+        _6 = &(_4.0: usize);
+        StorageLive(_7);
+        _7 = &(_4.1: usize);
         StorageLive(_8);
+        _8 = (_4.0: usize);
         StorageLive(_9);
-        StorageLive(_7);
-        StorageLive(_15);
-        StorageLive(_16);
-        StorageLive(_5);
-        _5 = (_4.0: usize);
-        StorageLive(_6);
-        _6 = (_4.1: usize);
-        _7 = Lt(move _5, move _6);
-        StorageDead(_6);
-        StorageDead(_5);
-        switchInt(move _7) -> [0: bb2, otherwise: bb3];
+        _9 = (_4.1: usize);
+        _10 = Lt(move _8, move _9);
+        StorageDead(_9);
+        StorageDead(_8);
+        switchInt(move _10) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        StorageDead(_16);
-        StorageDead(_15);
-        _8 = Option::<usize>::None;
+        StorageDead(_7);
+        StorageDead(_6);
+        _11 = Option::<usize>::None;
         goto -> bb5;
     }
 
     bb3: {
-        StorageDead(_16);
-        StorageDead(_15);
-        _9 = (_4.0: usize);
-        StorageLive(_10);
-        _10 = <usize as Step>::forward_unchecked(_9, const 1_usize) -> [return: bb4, unwind continue];
+        StorageDead(_7);
+        StorageDead(_6);
+        _12 = (_4.0: usize);
+        StorageLive(_13);
+        _13 = <usize as Step>::forward_unchecked(_12, const 1_usize) -> [return: bb4, unwind continue];
     }
 
     bb4: {
-        (_4.0: usize) = move _10;
-        StorageDead(_10);
-        _8 = Option::<usize>::Some(_9);
+        (_4.0: usize) = move _13;
+        StorageDead(_13);
+        _11 = Option::<usize>::Some(_12);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_7);
-        StorageDead(_9);
-        _11 = discriminant(_8);
-        switchInt(move _11) -> [0: bb6, 1: bb7, otherwise: bb9];
+        StorageDead(_10);
+        StorageDead(_12);
+        _14 = discriminant(_11);
+        switchInt(move _14) -> [0: bb6, 1: bb7, otherwise: bb9];
     }
 
     bb6: {
-        StorageDead(_8);
+        StorageDead(_11);
         StorageDead(_4);
         return;
     }
 
     bb7: {
-        _12 = ((_8 as Some).0: usize);
-        _13 = opaque::<usize>(move _12) -> [return: bb8, unwind continue];
+        _15 = ((_11 as Some).0: usize);
+        _16 = opaque::<usize>(move _15) -> [return: bb8, unwind continue];
     }
 
     bb8: {
-        StorageDead(_8);
+        StorageDead(_11);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
index c30df7425d2..30bdc131090 100644
--- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
@@ -6,16 +6,15 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     let mut _0: ();
     let mut _3: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
     let mut _4: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
-    let mut _5: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
-    let mut _6: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
-    let mut _7: std::option::Option<U>;
-    let mut _8: isize;
-    let _10: ();
+    let mut _5: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
+    let mut _6: std::option::Option<U>;
+    let mut _7: isize;
+    let _9: ();
     scope 1 {
-        debug iter => _5;
-        let _9: U;
+        debug iter => _4;
+        let _8: U;
         scope 2 {
-            debug x => _9;
+            debug x => _8;
         }
     }
     scope 3 (inlined <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as IntoIterator>::into_iter) {
@@ -23,50 +22,45 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     }
 
     bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
         _3 = <impl Iterator<Item = T> as Iterator>::map::<U, impl Fn(T) -> U>(move _1, move _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
+        StorageLive(_4);
         _4 = move _3;
-        StorageDead(_3);
-        StorageLive(_5);
-        _5 = move _4;
         goto -> bb2;
     }
 
     bb2: {
-        StorageLive(_7);
         StorageLive(_6);
-        _6 = &mut _5;
-        _7 = <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next(move _6) -> [return: bb3, unwind: bb9];
+        StorageLive(_5);
+        _5 = &mut _4;
+        _6 = <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next(move _5) -> [return: bb3, unwind: bb9];
     }
 
     bb3: {
-        StorageDead(_6);
-        _8 = discriminant(_7);
-        switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb8];
+        StorageDead(_5);
+        _7 = discriminant(_6);
+        switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb8];
     }
 
     bb4: {
-        StorageDead(_7);
-        drop(_5) -> [return: bb5, unwind continue];
+        StorageDead(_6);
+        drop(_4) -> [return: bb5, unwind continue];
     }
 
     bb5: {
-        StorageDead(_5);
         StorageDead(_4);
         return;
     }
 
     bb6: {
-        _9 = move ((_7 as Some).0: U);
-        _10 = opaque::<U>(move _9) -> [return: bb7, unwind: bb9];
+        _8 = move ((_6 as Some).0: U);
+        _9 = opaque::<U>(move _8) -> [return: bb7, unwind: bb9];
     }
 
     bb7: {
-        StorageDead(_7);
+        StorageDead(_6);
         goto -> bb2;
     }
 
@@ -75,7 +69,7 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     }
 
     bb9 (cleanup): {
-        drop(_5) -> [return: bb10, unwind terminate(cleanup)];
+        drop(_4) -> [return: bb10, unwind terminate(cleanup)];
     }
 
     bb10 (cleanup): {
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
index 9664ccfb094..91c3731f492 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -7,37 +7,37 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     let mut _0: ();
     let mut _4: std::ops::Range<u32>;
     let mut _5: std::ops::Range<u32>;
-    let mut _9: std::option::Option<u32>;
-    let mut _12: isize;
-    let mut _14: &impl Fn(u32);
-    let mut _15: (u32,);
-    let _16: ();
-    let mut _17: &mut std::ops::Range<u32>;
+    let mut _6: &mut std::ops::Range<u32>;
+    let mut _12: std::option::Option<u32>;
+    let mut _15: isize;
+    let mut _17: &impl Fn(u32);
+    let mut _18: (u32,);
+    let _19: ();
     scope 1 {
         debug iter => _5;
-        let _13: u32;
+        let _16: u32;
         scope 2 {
-            debug x => _13;
+            debug x => _16;
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) {
-            debug self => _17;
+            debug self => _6;
             scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) {
-                debug self => _17;
-                let mut _8: bool;
-                let _10: u32;
-                let mut _11: u32;
-                let mut _18: &u32;
-                let mut _19: &u32;
+                debug self => _6;
+                let mut _7: &u32;
+                let mut _8: &u32;
+                let mut _11: bool;
+                let _13: u32;
+                let mut _14: u32;
                 scope 6 {
-                    debug old => _10;
+                    debug old => _13;
                     scope 7 {
                     }
                 }
                 scope 8 (inlined cmp::impls::<impl PartialOrd for u32>::lt) {
-                    debug self => _18;
-                    debug other => _19;
-                    let mut _6: u32;
-                    let mut _7: u32;
+                    debug self => _7;
+                    debug other => _8;
+                    let mut _9: u32;
+                    let mut _10: u32;
                 }
             }
         }
@@ -54,52 +54,55 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb1: {
+        StorageLive(_12);
+        _6 = &mut _5;
+        StorageLive(_13);
+        StorageLive(_11);
+        StorageLive(_7);
+        _7 = &(_5.0: u32);
+        StorageLive(_8);
+        _8 = &(_5.1: u32);
         StorageLive(_9);
+        _9 = (_5.0: u32);
         StorageLive(_10);
-        StorageLive(_8);
-        StorageLive(_18);
-        StorageLive(_19);
-        StorageLive(_6);
-        _6 = (_5.0: u32);
-        StorageLive(_7);
-        _7 = (_5.1: u32);
-        _8 = Lt(move _6, move _7);
-        StorageDead(_7);
-        StorageDead(_6);
-        switchInt(move _8) -> [0: bb2, otherwise: bb3];
+        _10 = (_5.1: u32);
+        _11 = Lt(move _9, move _10);
+        StorageDead(_10);
+        StorageDead(_9);
+        switchInt(move _11) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        StorageDead(_19);
-        StorageDead(_18);
-        _9 = Option::<u32>::None;
+        StorageDead(_8);
+        StorageDead(_7);
+        _12 = Option::<u32>::None;
         goto -> bb5;
     }
 
     bb3: {
-        StorageDead(_19);
-        StorageDead(_18);
-        _10 = (_5.0: u32);
-        StorageLive(_11);
-        _11 = <u32 as Step>::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind unreachable];
+        StorageDead(_8);
+        StorageDead(_7);
+        _13 = (_5.0: u32);
+        StorageLive(_14);
+        _14 = <u32 as Step>::forward_unchecked(_13, const 1_usize) -> [return: bb4, unwind unreachable];
     }
 
     bb4: {
-        (_5.0: u32) = move _11;
-        StorageDead(_11);
-        _9 = Option::<u32>::Some(_10);
+        (_5.0: u32) = move _14;
+        StorageDead(_14);
+        _12 = Option::<u32>::Some(_13);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_8);
-        StorageDead(_10);
-        _12 = discriminant(_9);
-        switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageDead(_11);
+        StorageDead(_13);
+        _15 = discriminant(_12);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_9);
+        StorageDead(_12);
         StorageDead(_5);
         drop(_3) -> [return: bb7, unwind unreachable];
     }
@@ -109,18 +112,18 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb8: {
-        _13 = ((_9 as Some).0: u32);
-        StorageLive(_14);
-        _14 = &_3;
-        StorageLive(_15);
-        _15 = (_13,);
-        _16 = <impl Fn(u32) as Fn<(u32,)>>::call(move _14, move _15) -> [return: bb9, unwind unreachable];
+        _16 = ((_12 as Some).0: u32);
+        StorageLive(_17);
+        _17 = &_3;
+        StorageLive(_18);
+        _18 = (_16,);
+        _19 = <impl Fn(u32) as Fn<(u32,)>>::call(move _17, move _18) -> [return: bb9, unwind unreachable];
     }
 
     bb9: {
-        StorageDead(_15);
-        StorageDead(_14);
-        StorageDead(_9);
+        StorageDead(_18);
+        StorageDead(_17);
+        StorageDead(_12);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index dc8b46b6c08..f76de02c9d1 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -7,37 +7,37 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     let mut _0: ();
     let mut _4: std::ops::Range<u32>;
     let mut _5: std::ops::Range<u32>;
-    let mut _9: std::option::Option<u32>;
-    let mut _12: isize;
-    let mut _14: &impl Fn(u32);
-    let mut _15: (u32,);
-    let _16: ();
-    let mut _17: &mut std::ops::Range<u32>;
+    let mut _6: &mut std::ops::Range<u32>;
+    let mut _12: std::option::Option<u32>;
+    let mut _15: isize;
+    let mut _17: &impl Fn(u32);
+    let mut _18: (u32,);
+    let _19: ();
     scope 1 {
         debug iter => _5;
-        let _13: u32;
+        let _16: u32;
         scope 2 {
-            debug x => _13;
+            debug x => _16;
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) {
-            debug self => _17;
+            debug self => _6;
             scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) {
-                debug self => _17;
-                let mut _8: bool;
-                let _10: u32;
-                let mut _11: u32;
-                let mut _18: &u32;
-                let mut _19: &u32;
+                debug self => _6;
+                let mut _7: &u32;
+                let mut _8: &u32;
+                let mut _11: bool;
+                let _13: u32;
+                let mut _14: u32;
                 scope 6 {
-                    debug old => _10;
+                    debug old => _13;
                     scope 7 {
                     }
                 }
                 scope 8 (inlined cmp::impls::<impl PartialOrd for u32>::lt) {
-                    debug self => _18;
-                    debug other => _19;
-                    let mut _6: u32;
-                    let mut _7: u32;
+                    debug self => _7;
+                    debug other => _8;
+                    let mut _9: u32;
+                    let mut _10: u32;
                 }
             }
         }
@@ -54,52 +54,55 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb1: {
+        StorageLive(_12);
+        _6 = &mut _5;
+        StorageLive(_13);
+        StorageLive(_11);
+        StorageLive(_7);
+        _7 = &(_5.0: u32);
+        StorageLive(_8);
+        _8 = &(_5.1: u32);
         StorageLive(_9);
+        _9 = (_5.0: u32);
         StorageLive(_10);
-        StorageLive(_8);
-        StorageLive(_18);
-        StorageLive(_19);
-        StorageLive(_6);
-        _6 = (_5.0: u32);
-        StorageLive(_7);
-        _7 = (_5.1: u32);
-        _8 = Lt(move _6, move _7);
-        StorageDead(_7);
-        StorageDead(_6);
-        switchInt(move _8) -> [0: bb2, otherwise: bb3];
+        _10 = (_5.1: u32);
+        _11 = Lt(move _9, move _10);
+        StorageDead(_10);
+        StorageDead(_9);
+        switchInt(move _11) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        StorageDead(_19);
-        StorageDead(_18);
-        _9 = Option::<u32>::None;
+        StorageDead(_8);
+        StorageDead(_7);
+        _12 = Option::<u32>::None;
         goto -> bb5;
     }
 
     bb3: {
-        StorageDead(_19);
-        StorageDead(_18);
-        _10 = (_5.0: u32);
-        StorageLive(_11);
-        _11 = <u32 as Step>::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind: bb11];
+        StorageDead(_8);
+        StorageDead(_7);
+        _13 = (_5.0: u32);
+        StorageLive(_14);
+        _14 = <u32 as Step>::forward_unchecked(_13, const 1_usize) -> [return: bb4, unwind: bb11];
     }
 
     bb4: {
-        (_5.0: u32) = move _11;
-        StorageDead(_11);
-        _9 = Option::<u32>::Some(_10);
+        (_5.0: u32) = move _14;
+        StorageDead(_14);
+        _12 = Option::<u32>::Some(_13);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_8);
-        StorageDead(_10);
-        _12 = discriminant(_9);
-        switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageDead(_11);
+        StorageDead(_13);
+        _15 = discriminant(_12);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_9);
+        StorageDead(_12);
         StorageDead(_5);
         drop(_3) -> [return: bb7, unwind continue];
     }
@@ -109,18 +112,18 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb8: {
-        _13 = ((_9 as Some).0: u32);
-        StorageLive(_14);
-        _14 = &_3;
-        StorageLive(_15);
-        _15 = (_13,);
-        _16 = <impl Fn(u32) as Fn<(u32,)>>::call(move _14, move _15) -> [return: bb9, unwind: bb11];
+        _16 = ((_12 as Some).0: u32);
+        StorageLive(_17);
+        _17 = &_3;
+        StorageLive(_18);
+        _18 = (_16,);
+        _19 = <impl Fn(u32) as Fn<(u32,)>>::call(move _17, move _18) -> [return: bb9, unwind: bb11];
     }
 
     bb9: {
-        StorageDead(_15);
-        StorageDead(_14);
-        StorageDead(_9);
+        StorageDead(_18);
+        StorageDead(_17);
+        StorageDead(_12);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
index fff713b5a79..a7824f36d50 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
@@ -7,65 +7,67 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
         debug self => _1;
         scope 2 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) {
             debug self => _1;
-            let mut _4: bool;
-            let _5: u32;
-            let mut _6: u32;
-            let mut _7: &u32;
-            let mut _8: &u32;
+            let mut _2: &u32;
+            let mut _3: &u32;
+            let mut _6: bool;
+            let _7: u32;
+            let mut _8: u32;
             scope 3 {
-                debug old => _5;
+                debug old => _7;
                 scope 4 {
                 }
             }
             scope 5 (inlined cmp::impls::<impl PartialOrd for u32>::lt) {
-                debug self => _7;
-                debug other => _8;
-                let mut _2: u32;
-                let mut _3: u32;
+                debug self => _2;
+                debug other => _3;
+                let mut _4: u32;
+                let mut _5: u32;
             }
         }
     }
 
     bb0: {
-        StorageLive(_5);
-        StorageLive(_4);
         StorageLive(_7);
-        StorageLive(_8);
+        StorageLive(_6);
         StorageLive(_2);
-        _2 = ((*_1).0: u32);
+        _2 = &((*_1).0: u32);
         StorageLive(_3);
-        _3 = ((*_1).1: u32);
-        _4 = Lt(move _2, move _3);
-        StorageDead(_3);
-        StorageDead(_2);
-        switchInt(move _4) -> [0: bb1, otherwise: bb2];
+        _3 = &((*_1).1: u32);
+        StorageLive(_4);
+        _4 = ((*_1).0: u32);
+        StorageLive(_5);
+        _5 = ((*_1).1: u32);
+        _6 = Lt(move _4, move _5);
+        StorageDead(_5);
+        StorageDead(_4);
+        switchInt(move _6) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageDead(_8);
-        StorageDead(_7);
+        StorageDead(_3);
+        StorageDead(_2);
         _0 = Option::<u32>::None;
         goto -> bb4;
     }
 
     bb2: {
-        StorageDead(_8);
-        StorageDead(_7);
-        _5 = ((*_1).0: u32);
-        StorageLive(_6);
-        _6 = <u32 as Step>::forward_unchecked(_5, const 1_usize) -> [return: bb3, unwind unreachable];
+        StorageDead(_3);
+        StorageDead(_2);
+        _7 = ((*_1).0: u32);
+        StorageLive(_8);
+        _8 = <u32 as Step>::forward_unchecked(_7, const 1_usize) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        ((*_1).0: u32) = move _6;
-        StorageDead(_6);
-        _0 = Option::<u32>::Some(_5);
+        ((*_1).0: u32) = move _8;
+        StorageDead(_8);
+        _0 = Option::<u32>::Some(_7);
         goto -> bb4;
     }
 
     bb4: {
-        StorageDead(_4);
-        StorageDead(_5);
+        StorageDead(_6);
+        StorageDead(_7);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
index cc12c0122b7..83c9e6c1af2 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
@@ -7,65 +7,67 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
         debug self => _1;
         scope 2 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) {
             debug self => _1;
-            let mut _4: bool;
-            let _5: u32;
-            let mut _6: u32;
-            let mut _7: &u32;
-            let mut _8: &u32;
+            let mut _2: &u32;
+            let mut _3: &u32;
+            let mut _6: bool;
+            let _7: u32;
+            let mut _8: u32;
             scope 3 {
-                debug old => _5;
+                debug old => _7;
                 scope 4 {
                 }
             }
             scope 5 (inlined cmp::impls::<impl PartialOrd for u32>::lt) {
-                debug self => _7;
-                debug other => _8;
-                let mut _2: u32;
-                let mut _3: u32;
+                debug self => _2;
+                debug other => _3;
+                let mut _4: u32;
+                let mut _5: u32;
             }
         }
     }
 
     bb0: {
-        StorageLive(_5);
-        StorageLive(_4);
         StorageLive(_7);
-        StorageLive(_8);
+        StorageLive(_6);
         StorageLive(_2);
-        _2 = ((*_1).0: u32);
+        _2 = &((*_1).0: u32);
         StorageLive(_3);
-        _3 = ((*_1).1: u32);
-        _4 = Lt(move _2, move _3);
-        StorageDead(_3);
-        StorageDead(_2);
-        switchInt(move _4) -> [0: bb1, otherwise: bb2];
+        _3 = &((*_1).1: u32);
+        StorageLive(_4);
+        _4 = ((*_1).0: u32);
+        StorageLive(_5);
+        _5 = ((*_1).1: u32);
+        _6 = Lt(move _4, move _5);
+        StorageDead(_5);
+        StorageDead(_4);
+        switchInt(move _6) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageDead(_8);
-        StorageDead(_7);
+        StorageDead(_3);
+        StorageDead(_2);
         _0 = Option::<u32>::None;
         goto -> bb4;
     }
 
     bb2: {
-        StorageDead(_8);
-        StorageDead(_7);
-        _5 = ((*_1).0: u32);
-        StorageLive(_6);
-        _6 = <u32 as Step>::forward_unchecked(_5, const 1_usize) -> [return: bb3, unwind continue];
+        StorageDead(_3);
+        StorageDead(_2);
+        _7 = ((*_1).0: u32);
+        StorageLive(_8);
+        _8 = <u32 as Step>::forward_unchecked(_7, const 1_usize) -> [return: bb3, unwind continue];
     }
 
     bb3: {
-        ((*_1).0: u32) = move _6;
-        StorageDead(_6);
-        _0 = Option::<u32>::Some(_5);
+        ((*_1).0: u32) = move _8;
+        StorageDead(_8);
+        _0 = Option::<u32>::Some(_7);
         goto -> bb4;
     }
 
     bb4: {
-        StorageDead(_4);
-        StorageDead(_5);
+        StorageDead(_6);
+        StorageDead(_7);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
index 9c10e96b0ea..b35d3a105ba 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
@@ -10,74 +10,74 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
     let _8: &usize;
     let mut _9: &(usize, usize, usize, usize);
     let _10: &usize;
-    let _11: &usize;
-    let mut _16: bool;
-    let _17: &usize;
-    let mut _22: bool;
-    let _23: &usize;
-    let mut _28: bool;
-    let _29: &usize;
-    let mut _34: &&usize;
+    let mut _11: &&usize;
+    let _12: &usize;
+    let mut _13: &&usize;
+    let mut _18: bool;
+    let mut _19: &&usize;
+    let _20: &usize;
+    let mut _21: &&usize;
+    let mut _26: bool;
+    let mut _27: &&usize;
+    let _28: &usize;
+    let mut _29: &&usize;
+    let mut _34: bool;
     let mut _35: &&usize;
-    let mut _36: &&usize;
+    let _36: &usize;
     let mut _37: &&usize;
-    let mut _38: &&usize;
-    let mut _39: &&usize;
-    let mut _40: &&usize;
-    let mut _41: &&usize;
     scope 1 {
         debug a => _4;
         debug b => _6;
         debug c => _8;
         debug d => _10;
         scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _34;
-            debug other => _35;
-            let mut _12: &usize;
-            let mut _13: &usize;
+            debug self => _11;
+            debug other => _13;
+            let mut _14: &usize;
+            let mut _15: &usize;
             scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _12;
-                debug other => _13;
-                let mut _14: usize;
-                let mut _15: usize;
+                debug self => _14;
+                debug other => _15;
+                let mut _16: usize;
+                let mut _17: usize;
             }
         }
         scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _36;
-            debug other => _37;
-            let mut _18: &usize;
-            let mut _19: &usize;
+            debug self => _19;
+            debug other => _21;
+            let mut _22: &usize;
+            let mut _23: &usize;
             scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _18;
-                debug other => _19;
-                let mut _20: usize;
-                let mut _21: usize;
+                debug self => _22;
+                debug other => _23;
+                let mut _24: usize;
+                let mut _25: usize;
             }
         }
         scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _38;
-            debug other => _39;
-            let mut _24: &usize;
-            let mut _25: &usize;
-            scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _24;
-                debug other => _25;
-                let mut _26: usize;
-                let mut _27: usize;
-            }
-        }
-        scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _40;
-            debug other => _41;
+            debug self => _27;
+            debug other => _29;
             let mut _30: &usize;
             let mut _31: &usize;
-            scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) {
+            scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) {
                 debug self => _30;
                 debug other => _31;
                 let mut _32: usize;
                 let mut _33: usize;
             }
         }
+        scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) {
+            debug self => _35;
+            debug other => _37;
+            let mut _38: &usize;
+            let mut _39: &usize;
+            scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) {
+                debug self => _38;
+                debug other => _39;
+                let mut _40: usize;
+                let mut _41: usize;
+            }
+        }
     }
 
     bb0: {
@@ -93,139 +93,147 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
         StorageLive(_10);
         _9 = deref_copy (*_2);
         _10 = &((*_9).3: usize);
-        StorageLive(_16);
-        StorageLive(_34);
-        StorageLive(_35);
+        StorageLive(_18);
         StorageLive(_11);
-        _11 = _8;
-        StorageLive(_12);
+        _11 = &_4;
         StorageLive(_13);
-        _12 = deref_copy _4;
-        _13 = deref_copy _11;
+        StorageLive(_12);
+        _12 = _8;
+        _13 = &_12;
         StorageLive(_14);
-        _14 = (*_12);
         StorageLive(_15);
-        _15 = (*_13);
-        _16 = Le(move _14, move _15);
+        _14 = deref_copy _4;
+        _15 = deref_copy _12;
+        StorageLive(_16);
+        _16 = (*_14);
+        StorageLive(_17);
+        _17 = (*_15);
+        _18 = Le(move _16, move _17);
+        StorageDead(_17);
+        StorageDead(_16);
         StorageDead(_15);
         StorageDead(_14);
-        StorageDead(_13);
-        StorageDead(_12);
-        switchInt(move _16) -> [0: bb1, otherwise: bb2];
+        switchInt(move _18) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
+        StorageDead(_12);
+        StorageDead(_13);
         StorageDead(_11);
-        StorageDead(_35);
-        StorageDead(_34);
         goto -> bb4;
     }
 
     bb2: {
+        StorageDead(_12);
+        StorageDead(_13);
         StorageDead(_11);
-        StorageDead(_35);
-        StorageDead(_34);
-        StorageLive(_22);
-        StorageLive(_36);
-        StorageLive(_37);
-        StorageLive(_17);
-        _17 = _6;
-        StorageLive(_18);
+        StorageLive(_26);
         StorageLive(_19);
-        _18 = deref_copy _10;
-        _19 = deref_copy _17;
-        StorageLive(_20);
-        _20 = (*_18);
+        _19 = &_10;
         StorageLive(_21);
-        _21 = (*_19);
-        _22 = Le(move _20, move _21);
-        StorageDead(_21);
-        StorageDead(_20);
-        StorageDead(_19);
-        StorageDead(_18);
-        switchInt(move _22) -> [0: bb3, otherwise: bb8];
-    }
-
-    bb3: {
-        StorageDead(_17);
-        StorageDead(_37);
-        StorageDead(_36);
-        goto -> bb4;
-    }
-
-    bb4: {
-        StorageLive(_28);
-        StorageLive(_38);
-        StorageLive(_39);
+        StorageLive(_20);
+        _20 = _6;
+        _21 = &_20;
+        StorageLive(_22);
         StorageLive(_23);
-        _23 = _4;
+        _22 = deref_copy _10;
+        _23 = deref_copy _20;
         StorageLive(_24);
+        _24 = (*_22);
         StorageLive(_25);
-        _24 = deref_copy _8;
-        _25 = deref_copy _23;
-        StorageLive(_26);
-        _26 = (*_24);
-        StorageLive(_27);
-        _27 = (*_25);
-        _28 = Le(move _26, move _27);
-        StorageDead(_27);
-        StorageDead(_26);
+        _25 = (*_23);
+        _26 = Le(move _24, move _25);
         StorageDead(_25);
         StorageDead(_24);
-        switchInt(move _28) -> [0: bb5, otherwise: bb6];
+        StorageDead(_23);
+        StorageDead(_22);
+        switchInt(move _26) -> [0: bb3, otherwise: bb8];
     }
 
-    bb5: {
-        StorageDead(_23);
-        StorageDead(_39);
-        StorageDead(_38);
-        _0 = const false;
-        goto -> bb7;
+    bb3: {
+        StorageDead(_20);
+        StorageDead(_21);
+        StorageDead(_19);
+        goto -> bb4;
     }
 
-    bb6: {
-        StorageDead(_23);
-        StorageDead(_39);
-        StorageDead(_38);
-        StorageLive(_40);
-        StorageLive(_41);
+    bb4: {
+        StorageLive(_34);
+        StorageLive(_27);
+        _27 = &_8;
         StorageLive(_29);
-        _29 = _10;
+        StorageLive(_28);
+        _28 = _4;
+        _29 = &_28;
         StorageLive(_30);
         StorageLive(_31);
-        _30 = deref_copy _6;
-        _31 = deref_copy _29;
+        _30 = deref_copy _8;
+        _31 = deref_copy _28;
         StorageLive(_32);
         _32 = (*_30);
         StorageLive(_33);
         _33 = (*_31);
-        _0 = Le(move _32, move _33);
+        _34 = Le(move _32, move _33);
         StorageDead(_33);
         StorageDead(_32);
         StorageDead(_31);
         StorageDead(_30);
+        switchInt(move _34) -> [0: bb5, otherwise: bb6];
+    }
+
+    bb5: {
+        StorageDead(_28);
         StorageDead(_29);
+        StorageDead(_27);
+        _0 = const false;
+        goto -> bb7;
+    }
+
+    bb6: {
+        StorageDead(_28);
+        StorageDead(_29);
+        StorageDead(_27);
+        StorageLive(_35);
+        _35 = &_6;
+        StorageLive(_37);
+        StorageLive(_36);
+        _36 = _10;
+        _37 = &_36;
+        StorageLive(_38);
+        StorageLive(_39);
+        _38 = deref_copy _6;
+        _39 = deref_copy _36;
+        StorageLive(_40);
+        _40 = (*_38);
+        StorageLive(_41);
+        _41 = (*_39);
+        _0 = Le(move _40, move _41);
         StorageDead(_41);
         StorageDead(_40);
+        StorageDead(_39);
+        StorageDead(_38);
+        StorageDead(_36);
+        StorageDead(_37);
+        StorageDead(_35);
         goto -> bb7;
     }
 
     bb7: {
-        StorageDead(_28);
+        StorageDead(_34);
         goto -> bb9;
     }
 
     bb8: {
-        StorageDead(_17);
-        StorageDead(_37);
-        StorageDead(_36);
+        StorageDead(_20);
+        StorageDead(_21);
+        StorageDead(_19);
         _0 = const true;
         goto -> bb9;
     }
 
     bb9: {
-        StorageDead(_22);
-        StorageDead(_16);
+        StorageDead(_26);
+        StorageDead(_18);
         StorageDead(_10);
         StorageDead(_8);
         StorageDead(_6);
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
index 2fd669aeeb6..729841ec5ea 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
@@ -19,11 +19,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
                 debug slice => _5;
                 let mut _7: *mut u32;
                 let mut _8: *mut u32;
-                let _15: usize;
-                let _16: usize;
                 scope 4 {
-                    debug ((this: std::ops::Range<usize>).0: usize) => _15;
-                    debug ((this: std::ops::Range<usize>).1: usize) => _16;
+                    debug ((this: std::ops::Range<usize>).0: usize) => _3;
+                    debug ((this: std::ops::Range<usize>).1: usize) => _4;
                     scope 5 {
                         let _6: usize;
                         scope 6 {
@@ -56,8 +54,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
                             }
                         }
                         scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
-                            debug ((this: std::ops::Range<usize>).0: usize) => _15;
-                            debug ((this: std::ops::Range<usize>).1: usize) => _16;
+                            debug ((this: std::ops::Range<usize>).0: usize) => _3;
+                            debug ((this: std::ops::Range<usize>).1: usize) => _4;
                             debug slice => _5;
                             scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
                                 debug self => _5;
@@ -82,8 +80,6 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
         _5 = &raw mut (*_1);
         StorageLive(_6);
         StorageLive(_14);
-        StorageLive(_15);
-        StorageLive(_16);
         _6 = SubUnchecked(_4, _3);
         StorageLive(_8);
         StorageLive(_7);
@@ -104,8 +100,6 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
         StorageDead(_12);
         StorageDead(_9);
         StorageDead(_8);
-        StorageDead(_16);
-        StorageDead(_15);
         StorageDead(_14);
         StorageDead(_6);
         StorageDead(_5);
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
index 2fd669aeeb6..729841ec5ea 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
@@ -19,11 +19,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
                 debug slice => _5;
                 let mut _7: *mut u32;
                 let mut _8: *mut u32;
-                let _15: usize;
-                let _16: usize;
                 scope 4 {
-                    debug ((this: std::ops::Range<usize>).0: usize) => _15;
-                    debug ((this: std::ops::Range<usize>).1: usize) => _16;
+                    debug ((this: std::ops::Range<usize>).0: usize) => _3;
+                    debug ((this: std::ops::Range<usize>).1: usize) => _4;
                     scope 5 {
                         let _6: usize;
                         scope 6 {
@@ -56,8 +54,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
                             }
                         }
                         scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
-                            debug ((this: std::ops::Range<usize>).0: usize) => _15;
-                            debug ((this: std::ops::Range<usize>).1: usize) => _16;
+                            debug ((this: std::ops::Range<usize>).0: usize) => _3;
+                            debug ((this: std::ops::Range<usize>).1: usize) => _4;
                             debug slice => _5;
                             scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
                                 debug self => _5;
@@ -82,8 +80,6 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
         _5 = &raw mut (*_1);
         StorageLive(_6);
         StorageLive(_14);
-        StorageLive(_15);
-        StorageLive(_16);
         _6 = SubUnchecked(_4, _3);
         StorageLive(_8);
         StorageLive(_7);
@@ -104,8 +100,6 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
         StorageDead(_12);
         StorageDead(_9);
         StorageDead(_8);
-        StorageDead(_16);
-        StorageDead(_15);
         StorageDead(_14);
         StorageDead(_6);
         StorageDead(_5);
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir
index df6d2263dc3..d97c96ac8a0 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir
@@ -7,17 +7,13 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] {
     scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) {
         debug self => _1;
         debug index => _2;
-        let _3: &[u32];
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind unreachable];
+        _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind unreachable];
     }
 
     bb1: {
-        _0 = _3;
-        StorageDead(_3);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir
index cc1795c3f97..4a976002fa5 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir
@@ -7,17 +7,13 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] {
     scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) {
         debug self => _1;
         debug index => _2;
-        let _3: &[u32];
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind continue];
+        _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
-        _0 = _3;
-        StorageDead(_3);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
index 4afe2eda188..ac1de7b4c90 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
@@ -7,43 +7,43 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     let mut _3: usize;
     let mut _4: std::ops::Range<usize>;
     let mut _5: std::ops::Range<usize>;
-    let mut _9: std::option::Option<usize>;
-    let mut _12: isize;
-    let mut _14: usize;
-    let mut _15: bool;
-    let mut _17: &impl Fn(usize, &T);
-    let mut _18: (usize, &T);
-    let _19: ();
-    let mut _20: &mut std::ops::Range<usize>;
+    let mut _6: &mut std::ops::Range<usize>;
+    let mut _12: std::option::Option<usize>;
+    let mut _15: isize;
+    let mut _17: usize;
+    let mut _18: bool;
+    let mut _20: &impl Fn(usize, &T);
+    let mut _21: (usize, &T);
+    let _22: ();
     scope 1 {
         debug iter => _5;
-        let _13: usize;
+        let _16: usize;
         scope 2 {
-            debug i => _13;
-            let _16: &T;
+            debug i => _16;
+            let _19: &T;
             scope 3 {
-                debug x => _16;
+                debug x => _19;
             }
         }
         scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
-            debug self => _20;
+            debug self => _6;
             scope 6 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) {
-                debug self => _20;
-                let mut _8: bool;
-                let _10: usize;
-                let mut _11: usize;
-                let mut _21: &usize;
-                let mut _22: &usize;
+                debug self => _6;
+                let mut _7: &usize;
+                let mut _8: &usize;
+                let mut _11: bool;
+                let _13: usize;
+                let mut _14: usize;
                 scope 7 {
-                    debug old => _10;
+                    debug old => _13;
                     scope 8 {
                     }
                 }
                 scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::lt) {
-                    debug self => _21;
-                    debug other => _22;
-                    let mut _6: usize;
-                    let mut _7: usize;
+                    debug self => _7;
+                    debug other => _8;
+                    let mut _9: usize;
+                    let mut _10: usize;
                 }
             }
         }
@@ -63,52 +63,55 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb1: {
+        StorageLive(_12);
+        _6 = &mut _5;
+        StorageLive(_13);
+        StorageLive(_11);
+        StorageLive(_7);
+        _7 = &(_5.0: usize);
+        StorageLive(_8);
+        _8 = &(_5.1: usize);
         StorageLive(_9);
+        _9 = (_5.0: usize);
         StorageLive(_10);
-        StorageLive(_8);
-        StorageLive(_21);
-        StorageLive(_22);
-        StorageLive(_6);
-        _6 = (_5.0: usize);
-        StorageLive(_7);
-        _7 = (_5.1: usize);
-        _8 = Lt(move _6, move _7);
-        StorageDead(_7);
-        StorageDead(_6);
-        switchInt(move _8) -> [0: bb2, otherwise: bb3];
+        _10 = (_5.1: usize);
+        _11 = Lt(move _9, move _10);
+        StorageDead(_10);
+        StorageDead(_9);
+        switchInt(move _11) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        StorageDead(_22);
-        StorageDead(_21);
-        _9 = Option::<usize>::None;
+        StorageDead(_8);
+        StorageDead(_7);
+        _12 = Option::<usize>::None;
         goto -> bb5;
     }
 
     bb3: {
-        StorageDead(_22);
-        StorageDead(_21);
-        _10 = (_5.0: usize);
-        StorageLive(_11);
-        _11 = <usize as Step>::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind unreachable];
+        StorageDead(_8);
+        StorageDead(_7);
+        _13 = (_5.0: usize);
+        StorageLive(_14);
+        _14 = <usize as Step>::forward_unchecked(_13, const 1_usize) -> [return: bb4, unwind unreachable];
     }
 
     bb4: {
-        (_5.0: usize) = move _11;
-        StorageDead(_11);
-        _9 = Option::<usize>::Some(_10);
+        (_5.0: usize) = move _14;
+        StorageDead(_14);
+        _12 = Option::<usize>::Some(_13);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_8);
-        StorageDead(_10);
-        _12 = discriminant(_9);
-        switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb11];
+        StorageDead(_11);
+        StorageDead(_13);
+        _15 = discriminant(_12);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb11];
     }
 
     bb6: {
-        StorageDead(_9);
+        StorageDead(_12);
         StorageDead(_5);
         drop(_2) -> [return: bb7, unwind unreachable];
     }
@@ -118,25 +121,25 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb8: {
-        _13 = ((_9 as Some).0: usize);
-        _14 = Len((*_1));
-        _15 = Lt(_13, _14);
-        assert(move _15, "index out of bounds: the length is {} but the index is {}", move _14, _13) -> [success: bb9, unwind unreachable];
+        _16 = ((_12 as Some).0: usize);
+        _17 = Len((*_1));
+        _18 = Lt(_16, _17);
+        assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, _16) -> [success: bb9, unwind unreachable];
     }
 
     bb9: {
-        _16 = &(*_1)[_13];
-        StorageLive(_17);
-        _17 = &_2;
-        StorageLive(_18);
-        _18 = (_13, _16);
-        _19 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _17, move _18) -> [return: bb10, unwind unreachable];
+        _19 = &(*_1)[_16];
+        StorageLive(_20);
+        _20 = &_2;
+        StorageLive(_21);
+        _21 = (_16, _19);
+        _22 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _20, move _21) -> [return: bb10, unwind unreachable];
     }
 
     bb10: {
-        StorageDead(_18);
-        StorageDead(_17);
-        StorageDead(_9);
+        StorageDead(_21);
+        StorageDead(_20);
+        StorageDead(_12);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index 48092608d9c..3c49ecf95a1 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -7,43 +7,43 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     let mut _3: usize;
     let mut _4: std::ops::Range<usize>;
     let mut _5: std::ops::Range<usize>;
-    let mut _9: std::option::Option<usize>;
-    let mut _12: isize;
-    let mut _14: usize;
-    let mut _15: bool;
-    let mut _17: &impl Fn(usize, &T);
-    let mut _18: (usize, &T);
-    let _19: ();
-    let mut _20: &mut std::ops::Range<usize>;
+    let mut _6: &mut std::ops::Range<usize>;
+    let mut _12: std::option::Option<usize>;
+    let mut _15: isize;
+    let mut _17: usize;
+    let mut _18: bool;
+    let mut _20: &impl Fn(usize, &T);
+    let mut _21: (usize, &T);
+    let _22: ();
     scope 1 {
         debug iter => _5;
-        let _13: usize;
+        let _16: usize;
         scope 2 {
-            debug i => _13;
-            let _16: &T;
+            debug i => _16;
+            let _19: &T;
             scope 3 {
-                debug x => _16;
+                debug x => _19;
             }
         }
         scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
-            debug self => _20;
+            debug self => _6;
             scope 6 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) {
-                debug self => _20;
-                let mut _8: bool;
-                let _10: usize;
-                let mut _11: usize;
-                let mut _21: &usize;
-                let mut _22: &usize;
+                debug self => _6;
+                let mut _7: &usize;
+                let mut _8: &usize;
+                let mut _11: bool;
+                let _13: usize;
+                let mut _14: usize;
                 scope 7 {
-                    debug old => _10;
+                    debug old => _13;
                     scope 8 {
                     }
                 }
                 scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::lt) {
-                    debug self => _21;
-                    debug other => _22;
-                    let mut _6: usize;
-                    let mut _7: usize;
+                    debug self => _7;
+                    debug other => _8;
+                    let mut _9: usize;
+                    let mut _10: usize;
                 }
             }
         }
@@ -63,52 +63,55 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb1: {
+        StorageLive(_12);
+        _6 = &mut _5;
+        StorageLive(_13);
+        StorageLive(_11);
+        StorageLive(_7);
+        _7 = &(_5.0: usize);
+        StorageLive(_8);
+        _8 = &(_5.1: usize);
         StorageLive(_9);
+        _9 = (_5.0: usize);
         StorageLive(_10);
-        StorageLive(_8);
-        StorageLive(_21);
-        StorageLive(_22);
-        StorageLive(_6);
-        _6 = (_5.0: usize);
-        StorageLive(_7);
-        _7 = (_5.1: usize);
-        _8 = Lt(move _6, move _7);
-        StorageDead(_7);
-        StorageDead(_6);
-        switchInt(move _8) -> [0: bb2, otherwise: bb3];
+        _10 = (_5.1: usize);
+        _11 = Lt(move _9, move _10);
+        StorageDead(_10);
+        StorageDead(_9);
+        switchInt(move _11) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        StorageDead(_22);
-        StorageDead(_21);
-        _9 = Option::<usize>::None;
+        StorageDead(_8);
+        StorageDead(_7);
+        _12 = Option::<usize>::None;
         goto -> bb5;
     }
 
     bb3: {
-        StorageDead(_22);
-        StorageDead(_21);
-        _10 = (_5.0: usize);
-        StorageLive(_11);
-        _11 = <usize as Step>::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind: bb12];
+        StorageDead(_8);
+        StorageDead(_7);
+        _13 = (_5.0: usize);
+        StorageLive(_14);
+        _14 = <usize as Step>::forward_unchecked(_13, const 1_usize) -> [return: bb4, unwind: bb12];
     }
 
     bb4: {
-        (_5.0: usize) = move _11;
-        StorageDead(_11);
-        _9 = Option::<usize>::Some(_10);
+        (_5.0: usize) = move _14;
+        StorageDead(_14);
+        _12 = Option::<usize>::Some(_13);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_8);
-        StorageDead(_10);
-        _12 = discriminant(_9);
-        switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb11];
+        StorageDead(_11);
+        StorageDead(_13);
+        _15 = discriminant(_12);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb11];
     }
 
     bb6: {
-        StorageDead(_9);
+        StorageDead(_12);
         StorageDead(_5);
         drop(_2) -> [return: bb7, unwind continue];
     }
@@ -118,25 +121,25 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb8: {
-        _13 = ((_9 as Some).0: usize);
-        _14 = Len((*_1));
-        _15 = Lt(_13, _14);
-        assert(move _15, "index out of bounds: the length is {} but the index is {}", move _14, _13) -> [success: bb9, unwind: bb12];
+        _16 = ((_12 as Some).0: usize);
+        _17 = Len((*_1));
+        _18 = Lt(_16, _17);
+        assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, _16) -> [success: bb9, unwind: bb12];
     }
 
     bb9: {
-        _16 = &(*_1)[_13];
-        StorageLive(_17);
-        _17 = &_2;
-        StorageLive(_18);
-        _18 = (_13, _16);
-        _19 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _17, move _18) -> [return: bb10, unwind: bb12];
+        _19 = &(*_1)[_16];
+        StorageLive(_20);
+        _20 = &_2;
+        StorageLive(_21);
+        _21 = (_16, _19);
+        _22 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _20, move _21) -> [return: bb10, unwind: bb12];
     }
 
     bb10: {
-        StorageDead(_18);
-        StorageDead(_17);
-        StorageDead(_9);
+        StorageDead(_21);
+        StorageDead(_20);
+        StorageDead(_12);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
index 549cb4f46a0..f3760463fe0 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
@@ -7,21 +7,21 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     let mut _13: std::slice::Iter<'_, T>;
     let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _15: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _17: std::option::Option<&T>;
-    let mut _18: isize;
-    let mut _20: &impl Fn(&T);
-    let mut _21: (&T,);
-    let _22: ();
-    let mut _23: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
+    let mut _16: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
+    let mut _18: std::option::Option<&T>;
+    let mut _19: isize;
+    let mut _21: &impl Fn(&T);
+    let mut _22: (&T,);
+    let _23: ();
     scope 1 {
         debug iter => _15;
-        let _19: &T;
+        let _20: &T;
         scope 2 {
-            debug x => _19;
+            debug x => _20;
         }
         scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            debug self => _23;
-            let mut _16: &mut std::slice::Iter<'_, T>;
+            debug self => _16;
+            let mut _17: &mut std::slice::Iter<'_, T>;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -153,20 +153,21 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb4: {
+        StorageLive(_18);
+        _16 = &mut _15;
         StorageLive(_17);
-        StorageLive(_16);
-        _16 = &mut (_15.0: std::slice::Iter<'_, T>);
-        _17 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _16) -> [return: bb5, unwind unreachable];
+        _17 = &mut (_15.0: std::slice::Iter<'_, T>);
+        _18 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind unreachable];
     }
 
     bb5: {
-        StorageDead(_16);
-        _18 = discriminant(_17);
-        switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageDead(_17);
+        _19 = discriminant(_18);
+        switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_17);
+        StorageDead(_18);
         StorageDead(_15);
         drop(_2) -> [return: bb7, unwind unreachable];
     }
@@ -176,18 +177,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb8: {
-        _19 = ((_17 as Some).0: &T);
-        StorageLive(_20);
-        _20 = &_2;
+        _20 = ((_18 as Some).0: &T);
         StorageLive(_21);
-        _21 = (_19,);
-        _22 = <impl Fn(&T) as Fn<(&T,)>>::call(move _20, move _21) -> [return: bb9, unwind unreachable];
+        _21 = &_2;
+        StorageLive(_22);
+        _22 = (_20,);
+        _23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind unreachable];
     }
 
     bb9: {
+        StorageDead(_22);
         StorageDead(_21);
-        StorageDead(_20);
-        StorageDead(_17);
+        StorageDead(_18);
         goto -> bb4;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
index 3cdc49f6056..e63f8b89308 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
@@ -7,21 +7,21 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     let mut _13: std::slice::Iter<'_, T>;
     let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _15: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _17: std::option::Option<&T>;
-    let mut _18: isize;
-    let mut _20: &impl Fn(&T);
-    let mut _21: (&T,);
-    let _22: ();
-    let mut _23: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
+    let mut _16: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
+    let mut _18: std::option::Option<&T>;
+    let mut _19: isize;
+    let mut _21: &impl Fn(&T);
+    let mut _22: (&T,);
+    let _23: ();
     scope 1 {
         debug iter => _15;
-        let _19: &T;
+        let _20: &T;
         scope 2 {
-            debug x => _19;
+            debug x => _20;
         }
         scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            debug self => _23;
-            let mut _16: &mut std::slice::Iter<'_, T>;
+            debug self => _16;
+            let mut _17: &mut std::slice::Iter<'_, T>;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -153,20 +153,21 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb4: {
+        StorageLive(_18);
+        _16 = &mut _15;
         StorageLive(_17);
-        StorageLive(_16);
-        _16 = &mut (_15.0: std::slice::Iter<'_, T>);
-        _17 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _16) -> [return: bb5, unwind: bb11];
+        _17 = &mut (_15.0: std::slice::Iter<'_, T>);
+        _18 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind: bb11];
     }
 
     bb5: {
-        StorageDead(_16);
-        _18 = discriminant(_17);
-        switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageDead(_17);
+        _19 = discriminant(_18);
+        switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_17);
+        StorageDead(_18);
         StorageDead(_15);
         drop(_2) -> [return: bb7, unwind continue];
     }
@@ -176,18 +177,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb8: {
-        _19 = ((_17 as Some).0: &T);
-        StorageLive(_20);
-        _20 = &_2;
+        _20 = ((_18 as Some).0: &T);
         StorageLive(_21);
-        _21 = (_19,);
-        _22 = <impl Fn(&T) as Fn<(&T,)>>::call(move _20, move _21) -> [return: bb9, unwind: bb11];
+        _21 = &_2;
+        StorageLive(_22);
+        _22 = (_20,);
+        _23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind: bb11];
     }
 
     bb9: {
+        StorageDead(_22);
         StorageDead(_21);
-        StorageDead(_20);
-        StorageDead(_17);
+        StorageDead(_18);
         goto -> bb4;
     }
 
diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
index 8fe361f2be4..1648f5dd8ca 100644
--- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
@@ -92,8 +92,8 @@
           StorageDead(_7);
 -         StorageDead(_6);
 -         StorageLive(_10);
-          StorageLive(_11);
-          StorageLive(_12);
+-         StorageLive(_11);
+-         StorageLive(_12);
           StorageLive(_13);
           _26 = const _;
           _13 = &(*_26);
@@ -105,8 +105,9 @@
       bb5: {
           StorageDead(_15);
           StorageDead(_13);
-          _11 = &(*_12);
-          _16 = Len((*_11));
+-         _11 = &(*_12);
+-         _16 = Len((*_11));
++         _16 = Len((*_12));
           _17 = const 3_usize;
           _18 = Ge(move _16, move _17);
           switchInt(move _18) -> [0: bb7, otherwise: bb6];
@@ -114,12 +115,15 @@
   
       bb6: {
           StorageLive(_19);
-          _19 = &(*_11)[1 of 3];
+-         _19 = &(*_11)[1 of 3];
++         _19 = &(*_12)[1 of 3];
           StorageLive(_20);
-          _20 = &(*_11)[2:-1];
+-         _20 = &(*_11)[2:-1];
++         _20 = &(*_12)[2:-1];
           StorageLive(_21);
-          _21 = &(*_11)[-1 of 3];
+-         _21 = &(*_11)[-1 of 3];
 -         _10 = const ();
++         _21 = &(*_12)[-1 of 3];
           StorageDead(_21);
           StorageDead(_20);
           StorageDead(_19);
@@ -132,8 +136,8 @@
       }
   
       bb8: {
-          StorageDead(_12);
-          StorageDead(_11);
+-         StorageDead(_12);
+-         StorageDead(_11);
 -         StorageDead(_10);
           StorageLive(_22);
           StorageLive(_23);
diff --git a/tests/run-make/const_fn_mir/Makefile b/tests/run-make/const_fn_mir/Makefile
index 6d72c122723..3399446130d 100644
--- a/tests/run-make/const_fn_mir/Makefile
+++ b/tests/run-make/const_fn_mir/Makefile
@@ -3,9 +3,4 @@ include ../tools.mk
 
 all:
 	$(RUSTC) main.rs --emit=mir -o "$(TMPDIR)"/dump.mir
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/dump.mir dump.mir
-else
-	$(DIFF) dump.mir "$(TMPDIR)"/dump.mir
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/dump.mir dump.mir
diff --git a/tests/run-make/issue-71519/Makefile b/tests/run-make/issue-71519/Makefile
deleted file mode 100644
index 0ee83328bb6..00000000000
--- a/tests/run-make/issue-71519/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-# ignore-msvc
-# needs-rust-lld
-# ignore-s390x lld does not yet support s390x as target
-all:
-	RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
-	$(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt
diff --git a/tests/run-make/issue-71519/main.rs b/tests/run-make/issue-71519/main.rs
deleted file mode 100644
index f8d09e89753..00000000000
--- a/tests/run-make/issue-71519/main.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// test linking using cc with rust-lld injected into search path as ld
-// see rust-lang/rust#71519 for more info
-
-fn main() {}
diff --git a/tests/run-make/metadata-dep-info/Makefile b/tests/run-make/metadata-dep-info/Makefile
index f9043f21433..d48cbe0f295 100644
--- a/tests/run-make/metadata-dep-info/Makefile
+++ b/tests/run-make/metadata-dep-info/Makefile
@@ -1,11 +1,5 @@
 include ../tools.mk
 
-ifdef RUSTC_BLESS_TEST
-    RUSTC_TEST_OP = cp
-else
-    RUSTC_TEST_OP = $(DIFF)
-endif
-
 all:
 	$(RUSTC) --emit=metadata,dep-info --crate-type lib dash-separated.rs -C extra-filename=_something-extra
 	# Strip TMPDIR since it is a machine specific absolute path
diff --git a/tests/run-make/overwrite-input/Makefile b/tests/run-make/overwrite-input/Makefile
index c62b5aab190..721bf62b26b 100644
--- a/tests/run-make/overwrite-input/Makefile
+++ b/tests/run-make/overwrite-input/Makefile
@@ -3,11 +3,5 @@ include ../tools.mk
 all:
 	$(RUSTC) main.rs -o main.rs 2> $(TMPDIR)/file.stderr || echo "failed successfully"
 	$(RUSTC) main.rs -o . 2> $(TMPDIR)/folder.stderr || echo "failed successfully"
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/file.stderr file.stderr
-	cp "$(TMPDIR)"/folder.stderr folder.stderr
-else
-	$(DIFF) file.stderr "$(TMPDIR)"/file.stderr
-	$(DIFF) folder.stderr "$(TMPDIR)"/folder.stderr
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/file.stderr file.stderr
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/folder.stderr folder.stderr
diff --git a/tests/run-make/raw-dylib-alt-calling-convention/Makefile b/tests/run-make/raw-dylib-alt-calling-convention/Makefile
index 1744c431f9c..14d23a5d201 100644
--- a/tests/run-make/raw-dylib-alt-calling-convention/Makefile
+++ b/tests/run-make/raw-dylib-alt-calling-convention/Makefile
@@ -16,17 +16,9 @@ else
 endif
 
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/output.txt output.txt
-else
-	$(DIFF) output.txt "$(TMPDIR)"/output.txt
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
 
 ifdef IS_MSVC
 	"$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/output.msvc.txt output.msvc.txt
-else
-	$(DIFF) output.msvc.txt "$(TMPDIR)"/output.msvc.txt
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.msvc.txt output.msvc.txt
 endif
diff --git a/tests/run-make/raw-dylib-import-name-type/Makefile b/tests/run-make/raw-dylib-import-name-type/Makefile
index 67152329807..901d3e861c2 100644
--- a/tests/run-make/raw-dylib-import-name-type/Makefile
+++ b/tests/run-make/raw-dylib-import-name-type/Makefile
@@ -14,9 +14,4 @@ else
 	$(CC) "$(TMPDIR)"/extern.obj extern.gnu.def --no-leading-underscore -shared -o "$(TMPDIR)"/extern.dll
 endif
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/output.txt output.txt
-else
-	$(DIFF) output.txt "$(TMPDIR)"/output.txt
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile
index 6d1d04bfd37..195b5fda56f 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile
@@ -27,9 +27,4 @@ else
 	$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
 endif
 	$(call RUN,driver) > "$(TMPDIR)"/output.txt
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/output.txt output.txt
-else
-	$(DIFF) output.txt "$(TMPDIR)"/output.txt
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
diff --git a/tests/run-make/raw-dylib-link-ordinal/Makefile b/tests/run-make/raw-dylib-link-ordinal/Makefile
index 374a0b59de3..49e959cdb5b 100644
--- a/tests/run-make/raw-dylib-link-ordinal/Makefile
+++ b/tests/run-make/raw-dylib-link-ordinal/Makefile
@@ -14,9 +14,4 @@ else
 	$(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
 endif
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/output.txt output.txt
-else
-	$(DIFF) output.txt "$(TMPDIR)"/output.txt
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
diff --git a/tests/run-make/raw-dylib-stdcall-ordinal/Makefile b/tests/run-make/raw-dylib-stdcall-ordinal/Makefile
index 178c15ab3de..70e4de62c1a 100644
--- a/tests/run-make/raw-dylib-stdcall-ordinal/Makefile
+++ b/tests/run-make/raw-dylib-stdcall-ordinal/Makefile
@@ -15,9 +15,4 @@ else
 	$(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
 endif
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/actual_output.txt expected_output.txt
-else
-	$(DIFF) expected_output.txt "$(TMPDIR)"/actual_output.txt
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/actual_output.txt expected_output.txt
diff --git a/tests/run-make/silly-file-names/Makefile b/tests/run-make/silly-file-names/Makefile
index a09bdb1c532..e51266c0880 100644
--- a/tests/run-make/silly-file-names/Makefile
+++ b/tests/run-make/silly-file-names/Makefile
@@ -3,12 +3,6 @@
 
 include ../tools.mk
 
-ifdef RUSTC_BLESS_TEST
-    RUSTC_TEST_OP = cp
-else
-    RUSTC_TEST_OP = $(DIFF)
-endif
-
 all:
 	echo '"comes from a file with a name that begins with <"' > "$(TMPDIR)/<leading-lt"
 	echo '"comes from a file with a name that ends with >"' > "$(TMPDIR)/trailing-gt>"
diff --git a/tests/run-make/tools.mk b/tests/run-make/tools.mk
index 6121a91e920..1d4e9111389 100644
--- a/tests/run-make/tools.mk
+++ b/tests/run-make/tools.mk
@@ -21,6 +21,28 @@ CGREP := "$(S)/src/etc/cat-and-grep.sh"
 # diff with common flags for multi-platform diffs against text output
 DIFF := diff -u --strip-trailing-cr
 
+# With RUSTC_TEST_OP you can elegantly support blessing of run-make tests. Do
+# like this in a Makefile recipe:
+#
+#   "$(TMPDIR)"/your-test > "$(TMPDIR)"/your-test.run.stdout
+#   $(RUSTC_TEST_OP) "$(TMPDIR)"/your-test.run.stdout your-test.run.stdout
+#
+# When running the test normally with
+#
+#   ./x test tests/run-make/your-test
+#
+# the actual output will be diffed against the expected output. When running in
+# bless-mode with
+#
+#   ./x test --bless tests/run-make/your-test
+#
+# the actual output will be blessed as the expected output.
+ifdef RUSTC_BLESS_TEST
+    RUSTC_TEST_OP = cp
+else
+    RUSTC_TEST_OP = $(DIFF)
+endif
+
 # Some of the Rust CI platforms use `/bin/dash` to run `shell` script in
 # Makefiles. Other platforms, including many developer platforms, default to
 # `/bin/bash`. (In many cases, `make` is actually using `/bin/sh`, but `sh`
diff --git a/tests/run-make/unknown-mod-stdin/Makefile b/tests/run-make/unknown-mod-stdin/Makefile
index c1931765382..313b0ba837e 100644
--- a/tests/run-make/unknown-mod-stdin/Makefile
+++ b/tests/run-make/unknown-mod-stdin/Makefile
@@ -4,12 +4,5 @@ include ../tools.mk
 
 all:
 	echo 'mod unknown;' | $(RUSTC) --crate-type rlib - >$(TMPDIR)/unknown-mod.stdout 2>$(TMPDIR)/unknown-mod.stderr || echo "failed successfully"
-
-# Bless like this: RUSTC_BLESS_TEST=1 ./x.py test tests/run-make/unknown-mod-stdin
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/unknown-mod.stdout unknown-mod.stdout
-	cp "$(TMPDIR)"/unknown-mod.stderr unknown-mod.stderr
-else
-	$(DIFF) unknown-mod.stdout "$(TMPDIR)"/unknown-mod.stdout
-	$(DIFF) unknown-mod.stderr "$(TMPDIR)"/unknown-mod.stderr
-endif
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/unknown-mod.stdout unknown-mod.stdout
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/unknown-mod.stderr unknown-mod.stderr
diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml
index 30b83f0da38..72e0bcd77e0 100644
--- a/tests/rustdoc-gui/anchors.goml
+++ b/tests/rustdoc-gui/anchors.goml
@@ -56,7 +56,7 @@ define-function: (
 
         assert-css: ("#top-doc-prose-title", {"color": |title_color|})
 
-        assert-css: (".sidebar a", {"color": |sidebar_link_color|})
+        assert-css: (".sidebar .block a", {"color": |sidebar_link_color|})
         assert-css: (".main-heading h1 a", {"color": |title_color|})
 
         // We move the cursor over the "Implementations" title so the anchor is displayed.
diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml
index 6d3eb66068c..bfc24c3260d 100644
--- a/tests/rustdoc-gui/huge-logo.goml
+++ b/tests/rustdoc-gui/huge-logo.goml
@@ -4,8 +4,8 @@ go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html"
 
 set-window-size: (1280, 1024)
 // offsetWidth = width of sidebar
-assert-property: (".sidebar .logo-container", {"offsetWidth": "200", "offsetHeight": 100})
-assert-property: (".sidebar .logo-container img", {"offsetWidth": "100", "offsetHeight": 100})
+assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "48", "offsetHeight": 48})
+assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 48})
 
 set-window-size: (400, 600)
 // offset = size + margin
diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml
index cd453aea276..696cab34dcc 100644
--- a/tests/rustdoc-gui/rust-logo.goml
+++ b/tests/rustdoc-gui/rust-logo.goml
@@ -1,18 +1,18 @@
 // This test ensures that the correct style is applied to the rust logo in the sidebar.
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
 
 define-function: (
     "check-logo",
     (theme, filter),
     block {
         // Going to the doc page.
-        go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+        go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
         // Changing theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
         assert-css: (".rust-logo", {"filter": |filter|})
         // Going to the source code page.
-        go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+        go-to: "file://" + |DOC_PATH| + "/src/staged_api/lib.rs.html"
         // Changing theme (since it's local files, the local storage works by folder).
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
@@ -26,6 +26,15 @@ define-function: (
         assert-false: ".rust-logo"
         // Check there is no filter.
         assert-css: (".sidebar .logo-container img", {"filter": "none"})
+        // Now we check that this page has no logo at all
+        go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+        assert-false: ".rust-logo"
+        assert-false: ".logo-container"
+        assert-false: ".sub-logo-container"
+        go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+        assert-false: ".rust-logo"
+        assert-false: ".logo-container"
+        assert-false: ".sub-logo-container"
     },
 )
 
diff --git a/tests/rustdoc-gui/search-result-impl-disambiguation.goml b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
new file mode 100644
index 00000000000..6d12032e891
--- /dev/null
+++ b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
@@ -0,0 +1,43 @@
+// ignore-tidy-linelength
+
+// Checks that, if a type has two methods with the same name, they both get
+// linked correctly.
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+
+// This should link to the inherent impl
+write: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#search-tabs"
+// Check the disambiguated link.
+assert-count: ("a.result-method", 1)
+assert-attribute: ("a.result-method", {
+    "href": "../test_docs/struct.ZyxwvutMethodDisambiguation.html#impl-ZyxwvutMethodDisambiguation/method.method_impl_disambiguation"
+})
+click: "a.result-method"
+wait-for: "#impl-ZyxwvutMethodDisambiguation"
+assert-document-property: ({
+    "URL": "struct.ZyxwvutMethodDisambiguation.html#method.method_impl_disambiguation"
+}, ENDS_WITH)
+assert: "section:target"
+
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+
+// This should link to the trait impl
+write: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#search-tabs"
+// Check the disambiguated link.
+assert-count: ("a.result-method", 1)
+assert-attribute: ("a.result-method", {
+    "href": "../test_docs/struct.ZyxwvutMethodDisambiguation.html#impl-ZyxwvutTrait-for-ZyxwvutMethodDisambiguation/method.method_impl_disambiguation"
+})
+click: "a.result-method"
+wait-for: "#impl-ZyxwvutMethodDisambiguation"
+assert-document-property: ({
+    "URL": "struct.ZyxwvutMethodDisambiguation.html#method.method_impl_disambiguation-1"
+}, ENDS_WITH)
+assert: "section:target"
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index 4b8337ace3a..d3a82d9ebe6 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -26,7 +26,7 @@ assert-css: (".sidebar", {"left": "0px"})
 // Make sure the "struct Foo" header is hidden, since the mobile topbar already does it.
 assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='Foo']/parent::h2", {"display": "none"})
 // Make sure the global navigation is still here.
-assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In test_docs']/parent::h2", {"display": "block"})
+assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In crate test_docs']/parent::h2", {"display": "block"})
 
 // Click elsewhere.
 click: "body"
@@ -50,7 +50,7 @@ assert-position: ("#method\.must_use", {"y": 46})
 // Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
 click: ".sidebar-menu-toggle"
 scroll-to: ".block.keyword li:nth-child(1)"
-compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543.19})
+compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544})
 
 // Now checking the background color of the sidebar.
 show-text: true
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 88546ed2549..cea4db1466b 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -174,14 +174,14 @@ click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"left": "-1000px"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
-assert-window-property: {"pageYOffset": "2542"}
+assert-window-property: {"pageYOffset": "2516"}
 // Expanding the sidebar...
 click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"left": "0px"})
 click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"left": "-1000px"})
 // The "scrollTop" property should be the same.
-assert-window-property: {"pageYOffset": "2542"}
+assert-window-property: {"pageYOffset": "2516"}
 
 // We now check that opening the sidebar and clicking a link will close it.
 // The behavior here on mobile is different than the behavior on desktop,
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 520481d3bba..eff66d803d2 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -50,9 +50,9 @@ set-local-storage: {"rustdoc-theme": "light"}
 // We reload the page so the local storage settings are being used.
 reload:
 
-assert-text: (".sidebar > .location", "Crate test_docs")
-// In modules, we only have one "location" element.
-assert-count: (".sidebar .location", 1)
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs")
+// Crate root has no "location" element
+assert-count: (".sidebar .location", 0)
 assert-count: (".sidebar h2", 1)
 assert-text: ("#all-types", "All Items")
 assert-css: ("#all-types", {"color": "#356da4"})
@@ -74,8 +74,9 @@ assert-text: ("#structs + .item-table .item-name > a", "Foo")
 click: "#structs + .item-table .item-name > a"
 
 // PAGE: struct.Foo.html
+assert-count: (".sidebar .sidebar-crate", 1)
 assert-count: (".sidebar .location", 1)
-assert-count: (".sidebar h2", 2)
+assert-count: (".sidebar h2", 3)
 // We check that there is no crate listed outside of the top level.
 assert-false: ".sidebar-elems > .crate"
 
@@ -94,7 +95,8 @@ click: ".sidebar-elems ul.crate > li:first-child > a"
 // PAGE: lib2/index.html
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
-assert-text: (".sidebar > .location", "Crate lib2")
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
+assert-count: (".sidebar .location", 0)
 // We check that we have the crates list and that the "current" on is now "lib2".
 assert-text: (".sidebar-elems ul.crate > li > a.current", "lib2")
 // We now go to the "foobar" function page.
@@ -108,22 +110,39 @@ click: "#functions + .item-table .item-name > a"
 
 // PAGE: fn.foobar.html
 // In items containing no items (like functions or constants) and in modules, we have no
-// "location" elements. Only the parent module h2.
+// "location" elements. Only the crate and optional parent module.
+// This page, being directly below the crate, only has its heading.
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-count: (".sidebar .location", 0)
 assert-count: (".sidebar h2", 1)
-assert-text: (".sidebar .sidebar-elems h2", "In lib2")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
 go-to: "./module/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-text: (".sidebar > .location", "Module module")
+assert-count: (".sidebar .location", 1)
+// Module page requires three headings:
+//   - Presistent crate branding (name and version)
+//   - Module name, followed by TOC for module headings
+//   - "In crate [name]" parent pointer, followed by sibling navigation
+assert-count: (".sidebar h2", 3)
+assert-text: (".sidebar > .sidebar-elems > h2", "In crate lib2")
+assert-property: (".sidebar > .sidebar-elems > h2 > a", {
+    "href": "/lib2/index.html",
+}, ENDS_WITH)
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
 go-to: "./sub_module/sub_sub_module/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
+assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-text: (".sidebar > .location", "Module sub_sub_module")
+assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module")
+assert-property: (".sidebar > .sidebar-elems > h2 > a", {
+    "href": "/module/sub_module/index.html",
+}, ENDS_WITH)
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems .crate"
 assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions")
@@ -152,14 +171,14 @@ assert-property: (".sidebar", {"clientWidth": "200"})
 
 // Checks that all.html and index.html have their sidebar link in the same place.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-store-property: (".sidebar .location a", {
+store-property: (".sidebar .sidebar-crate h2 a", {
     "clientWidth": index_sidebar_width,
     "clientHeight": index_sidebar_height,
     "offsetTop": index_sidebar_y,
     "offsetLeft": index_sidebar_x,
 })
 go-to: "file://" + |DOC_PATH| + "/test_docs/all.html"
-assert-property: (".sidebar .location a", {
+assert-property: (".sidebar .sidebar-crate h2 a", {
     "clientWidth": |index_sidebar_width|,
     "clientHeight": |index_sidebar_height|,
     "offsetTop": |index_sidebar_y|,
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index 0e4913cafb2..940851ea146 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@ set-window-size: (600, 800)
 assert-property: ("html", {"scrollTop": "0"})
 
 click: '//a[text() = "barbar" and @href="#5-7"]'
-assert-property: ("html", {"scrollTop": "149"})
+assert-property: ("html", {"scrollTop": "123"})
 click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "180"})
+assert-property: ("html", {"scrollTop": "154"})
 click: '//a[text() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "77"})
+assert-property: ("html", {"scrollTop": "51"})
 
 // We now check that clicking on lines doesn't change the scroll
 // Extra information: the "sub_fn" function header is on line 1.
 click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "77"})
+assert-property: ("html", {"scrollTop": "51"})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index f19e3ce80e1..ad57380ae25 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -89,9 +89,9 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
 // do anything (and certainly not add a `#NaN` to the URL!).
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
-assert-position: ("//*[@id='1']", {"x": 88, "y": 112})
+assert-position: ("//*[@id='1']", {"x": 88, "y": 86})
 // We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
-click: (87, 103)
+click: (87, 77)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 
 // Checking the source code sidebar.
@@ -163,16 +163,16 @@ assert-css: ("nav.sub", {"flex-direction": "row"})
 // To check this, we maintain the invariant:
 //
 // offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
-assert-property: ("nav.sub form", {"offsetTop": 28, "offsetHeight": 34})
-assert-property: ("#main-content", {"offsetTop": 90})
-// 28 = 90 - 34 - 28
+assert-property: ("nav.sub form", {"offsetTop": 15, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 64})
+// 15 = 64 - 34 - 15
 
 // Now do the same check on moderately-sized, tablet mobile.
 set-window-size: (700, 700)
 assert-css: ("nav.sub", {"flex-direction": "row"})
-assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
-assert-property: ("#main-content", {"offsetTop": 76})
-// 21 = 76 - 34 - 21
+assert-property: ("nav.sub form", {"offsetTop": 8, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 50})
+// 8 = 50 - 34 - 8
 
 // Check the sidebar directory entries have a marker and spacing (tablet).
 store-property: ("#src-sidebar > .title", {
@@ -198,7 +198,12 @@ call-function: ("check-sidebar-dir-entry", {
     "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
 })
 
+// The logo is not present on this page.
+assert-false: ".sub-logo-container > img"
+
+// Check the staged-api page instead, which does.
 // Now we check that the logo has a bottom margin so it's not stuck to the search input.
+go-to: "file://" + |DOC_PATH| + "/src/staged_api/lib.rs.html"
 assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"})
 store-property: (".sub-logo-container", {"clientHeight": logo_height})
 assert-position: (".search-form", {"y": |logo_height| + 8})
diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs
index 0c914470e28..9b5ad1c5ff3 100644
--- a/tests/rustdoc-gui/src/staged_api/lib.rs
+++ b/tests/rustdoc-gui/src/staged_api/lib.rs
@@ -1,6 +1,8 @@
 #![feature(staged_api)]
+#![feature(rustdoc_internals)]
 #![allow(internal_features)]
 #![stable(feature = "some_feature", since = "1.3.5")]
+#![doc(rust_logo)]
 
 #[stable(feature = "some_feature", since = "1.3.5")]
 pub struct Foo {}
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 38180aef762..5c91bcbb4ee 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -529,3 +529,21 @@ pub mod cfgs {
     /// Some docs.
     pub mod cfgs {}
 }
+
+pub struct ZyxwvutMethodDisambiguation;
+
+impl ZyxwvutMethodDisambiguation {
+    pub fn method_impl_disambiguation(&self) -> bool {
+        true
+    }
+}
+
+pub trait ZyxwvutTrait {
+    fn method_impl_disambiguation(&self, x: usize) -> usize;
+}
+
+impl ZyxwvutTrait for ZyxwvutMethodDisambiguation {
+    fn method_impl_disambiguation(&self, x: usize) -> usize {
+        x
+    }
+}
diff --git a/tests/rustdoc-js-std/simd-type-signatures.js b/tests/rustdoc-js-std/simd-type-signatures.js
new file mode 100644
index 00000000000..5c7cf372bce
--- /dev/null
+++ b/tests/rustdoc-js-std/simd-type-signatures.js
@@ -0,0 +1,70 @@
+// exact-check
+// ignore-order
+// ignore-tidy-linelength
+
+// This test case verifies that the href points at the correct impl
+
+const FILTER_CRATE = "std";
+
+const EXPECTED = [
+    {
+        'query': 'simd<i16>, simd<i16> -> simd<i16>',
+        'others': [
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'simd_max',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_max'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'simd_min',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_min'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'simd_clamp',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_clamp'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'saturating_add',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+LANES%3E/method.saturating_add'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'saturating_sub',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+LANES%3E/method.saturating_sub'
+            },
+        ],
+    },
+    {
+        'query': 'simd<i8>, simd<i8> -> simd<i8>',
+        'others': [
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'simd_max',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_max'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'simd_min',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_min'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'simd_clamp',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_clamp'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'saturating_add',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+LANES%3E/method.saturating_add'
+            },
+            {
+                'path': 'std::simd::prelude::Simd',
+                'name': 'saturating_sub',
+                'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+LANES%3E/method.saturating_sub'
+            },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/auxiliary/equivalent.rs b/tests/rustdoc-js/auxiliary/equivalent.rs
new file mode 100644
index 00000000000..a19b5a2d44d
--- /dev/null
+++ b/tests/rustdoc-js/auxiliary/equivalent.rs
@@ -0,0 +1,15 @@
+use std::borrow::Borrow;
+
+pub trait Equivalent<K: ?Sized> {
+    fn equivalent(&self, key: &K) -> bool;
+}
+
+impl<Q: ?Sized, K: ?Sized> Equivalent<K> for Q
+where
+    Q: Eq,
+    K: Borrow<Q>,
+{
+    fn equivalent(&self, key: &K) -> bool {
+        PartialEq::eq(self, key.borrow())
+    }
+}
diff --git a/tests/rustdoc-js/search-method-disambiguate.js b/tests/rustdoc-js/search-method-disambiguate.js
new file mode 100644
index 00000000000..70aa895f994
--- /dev/null
+++ b/tests/rustdoc-js/search-method-disambiguate.js
@@ -0,0 +1,28 @@
+// exact-check
+// ignore-order
+// ignore-tidy-linelength
+
+const FILTER_CRATE = "search_method_disambiguate";
+
+const EXPECTED = [
+    {
+        'query': 'MyTy -> bool',
+        'others': [
+            {
+                'path': 'search_method_disambiguate::MyTy',
+                'name': 'my_method',
+                'href': '../search_method_disambiguate/struct.MyTy.html#impl-X-for-MyTy%3Cbool%3E/method.my_method'
+            },
+        ],
+    },
+    {
+        'query': 'MyTy -> u8',
+        'others': [
+            {
+                'path': 'search_method_disambiguate::MyTy',
+                'name': 'my_method',
+                'href': '../search_method_disambiguate/struct.MyTy.html#impl-X-for-MyTy%3Cu8%3E/method.my_method'
+            },
+        ],
+    }
+];
diff --git a/tests/rustdoc-js/search-method-disambiguate.rs b/tests/rustdoc-js/search-method-disambiguate.rs
new file mode 100644
index 00000000000..ae884447a92
--- /dev/null
+++ b/tests/rustdoc-js/search-method-disambiguate.rs
@@ -0,0 +1,22 @@
+pub trait X {
+    type InnerType;
+    fn my_method(&self) -> Self::InnerType;
+}
+
+pub struct MyTy<T> {
+    pub t: T,
+}
+
+impl X for MyTy<bool> {
+    type InnerType = bool;
+    fn my_method(&self) -> bool {
+        self.t
+    }
+}
+
+impl X for MyTy<u8> {
+    type InnerType = u8;
+    fn my_method(&self) -> u8 {
+        self.t
+    }
+}
diff --git a/tests/rustdoc-js/search-non-local-trait-impl.js b/tests/rustdoc-js/search-non-local-trait-impl.js
new file mode 100644
index 00000000000..9ebeceb69f9
--- /dev/null
+++ b/tests/rustdoc-js/search-non-local-trait-impl.js
@@ -0,0 +1,9 @@
+// exact-check
+
+// This test ensures that methods from blanket impls of not available foreign traits
+// don't show up in the search results.
+
+const EXPECTED = {
+    'query': 'equivalent',
+    'others': [],
+};
diff --git a/tests/rustdoc-js/search-non-local-trait-impl.rs b/tests/rustdoc-js/search-non-local-trait-impl.rs
new file mode 100644
index 00000000000..462b75b0b13
--- /dev/null
+++ b/tests/rustdoc-js/search-non-local-trait-impl.rs
@@ -0,0 +1,8 @@
+// aux-crate:priv:equivalent=equivalent.rs
+// compile-flags: -Zunstable-options --extern equivalent
+// edition:2018
+
+extern crate equivalent;
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct LayoutError;
diff --git a/tests/rustdoc/auxiliary/enum-variant.rs b/tests/rustdoc/auxiliary/enum-variant.rs
new file mode 100644
index 00000000000..a0a7fd894f9
--- /dev/null
+++ b/tests/rustdoc/auxiliary/enum-variant.rs
@@ -0,0 +1,48 @@
+#![crate_name = "bar"]
+
+pub enum E {
+    A = 12,
+    B,
+    C = 1245,
+}
+
+pub enum F {
+    A,
+    B,
+}
+
+#[repr(u32)]
+pub enum G {
+    A = 12,
+    B,
+    C(u32),
+}
+
+pub enum H {
+    A,
+    C(u32),
+}
+
+#[repr(C)]
+pub enum N {
+    A,
+    B,
+}
+
+#[repr(C)]
+pub enum O {
+    A(u32),
+    B,
+}
+
+#[repr(u32)]
+pub enum P {
+    A,
+    B,
+}
+
+#[repr(u32)]
+pub enum Q {
+    A(u32),
+    B,
+}
diff --git a/tests/rustdoc/blanket-reexport-item.rs b/tests/rustdoc/blanket-reexport-item.rs
index 437f0001fcf..315a38c30c5 100644
--- a/tests/rustdoc/blanket-reexport-item.rs
+++ b/tests/rustdoc/blanket-reexport-item.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header"]' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-T"]//h3[@class="code-header"]' 'impl<T, U> Into<U> for T'
 pub struct S2 {}
 mod m {
     pub struct S {}
diff --git a/tests/rustdoc/const-effect-param.rs b/tests/rustdoc/const-effect-param.rs
new file mode 100644
index 00000000000..f50a9b96d81
--- /dev/null
+++ b/tests/rustdoc/const-effect-param.rs
@@ -0,0 +1,12 @@
+#![crate_name = "foo"]
+#![feature(effects, const_trait_impl)]
+
+#[const_trait]
+pub trait Tr {
+    fn f();
+}
+
+// @has foo/fn.g.html
+// @has - '//pre[@class="rust item-decl"]' 'pub const fn g<T: Tr>()'
+/// foo
+pub const fn g<T: ~const Tr>() {}
diff --git a/tests/rustdoc/const-fn-effects.rs b/tests/rustdoc/const-fn-effects.rs
new file mode 100644
index 00000000000..7c19b4b2c0c
--- /dev/null
+++ b/tests/rustdoc/const-fn-effects.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+#![feature(effects)]
+
+// @has foo/fn.bar.html
+// @has - '//pre[@class="rust item-decl"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+    2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+    pub const fn new() -> Foo {
+        Foo(0)
+    }
+}
diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc/const-generics/const-impl.rs
index 152b643bf4b..b424ea4b33c 100644
--- a/tests/rustdoc/const-generics/const-impl.rs
+++ b/tests/rustdoc/const-generics/const-impl.rs
@@ -31,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> {
 
 pub struct Escape<const S: &'static str>;
 
-// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr%23%22%3Cscript%3Ealert(%22Escape%22);%3C/script%3E%22%23%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+// @has foo/struct.Escape.html '//*[@id="impl-Escape%3C%22%3Cscript%3Ealert(%5C%22Escape%5C%22);%3C/script%3E%22%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
 impl Escape<r#"<script>alert("Escape");</script>"#> {
     pub fn f() {}
 }
diff --git a/tests/rustdoc/crate-version-escape.rs b/tests/rustdoc/crate-version-escape.rs
index 8413709f15e..f134d9baa7d 100644
--- a/tests/rustdoc/crate-version-escape.rs
+++ b/tests/rustdoc/crate-version-escape.rs
@@ -2,4 +2,4 @@
 
 #![crate_name = "foo"]
 
-// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>'
+// @has 'foo/index.html' '//*[@class="version"]' '<script>alert("hi")</script>'
diff --git a/tests/rustdoc/crate-version-extra.rs b/tests/rustdoc/crate-version-extra.rs
new file mode 100644
index 00000000000..72a2c4ba5f7
--- /dev/null
+++ b/tests/rustdoc/crate-version-extra.rs
@@ -0,0 +1,7 @@
+// compile-flags: '--crate-version=1.3.37-nightly (203c57dbe 2023-09-17)'
+
+#![crate_name="foo"]
+
+// main version next to logo, extra version data below it
+// @has 'foo/index.html' '//h2/span[@class="version"]' '1.3.37-nightly'
+// @has 'foo/index.html' '//nav[@class="sidebar"]/div[@class="version"]' '(203c57dbe 2023-09-17)'
diff --git a/tests/rustdoc/crate-version.rs b/tests/rustdoc/crate-version.rs
index 2592c98530f..d4be845b71e 100644
--- a/tests/rustdoc/crate-version.rs
+++ b/tests/rustdoc/crate-version.rs
@@ -1,3 +1,3 @@
 // compile-flags: --crate-version=1.3.37
 
-// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37'
+// @has 'crate_version/index.html' '//*[@class="version"]' '1.3.37'
diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum-variant-value.rs
new file mode 100644
index 00000000000..096f8cd4122
--- /dev/null
+++ b/tests/rustdoc/enum-variant-value.rs
@@ -0,0 +1,191 @@
+// This test ensures that the variant value is displayed with underscores but without
+// a type name at the end.
+
+// aux-build:enum-variant.rs
+
+#![crate_name = "foo"]
+
+extern crate bar;
+
+// In this case, since all variants are C-like variants and at least one of them
+// has its value set, we display values for all of them.
+
+// @has 'foo/enum.A.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 12,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 13,'
+// @has - '//*[@class="rust item-decl"]/code' 'C = 1_245,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 12$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 13$'
+// @matches - '//*[@id="variant.C"]/h3' '^C = 1_245$'
+pub enum A {
+    A = 12,
+    B,
+    C = 1245,
+}
+
+// In this case, all variants are C-like variants but none of them has its value set.
+// Therefore we don't display values.
+
+// @has 'foo/enum.B.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A,'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @matches - '//*[@id="variant.A"]/h3' '^A$'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+pub enum B {
+    A,
+    B,
+}
+
+// In this case, not all variants are C-like variants so we don't display values.
+
+// @has 'foo/enum.C.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 12,'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @has - '//*[@class="rust item-decl"]/code' 'C(u32),'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 12$'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+// @has - '//*[@id="variant.C"]/h3' 'C(u32)'
+#[repr(u32)]
+pub enum C {
+    A = 12,
+    B,
+    C(u32),
+}
+
+// In this case, not all variants are C-like variants and no C-like variant has its
+// value set, so we don't display values.
+
+// @has 'foo/enum.D.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A,'
+// @has - '//*[@class="rust item-decl"]/code' 'C(u32),'
+// @matches - '//*[@id="variant.A"]/h3' '^A$'
+// @has - '//*[@id="variant.C"]/h3' 'C(u32)'
+pub enum D {
+    A,
+    C(u32),
+}
+
+// @has 'foo/enum.E.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 12,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 13,'
+// @has - '//*[@class="rust item-decl"]/code' 'C = 1_245,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 12$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 13$'
+// @matches - '//*[@id="variant.C"]/h3' '^C = 1_245$'
+pub use bar::E;
+
+// @has 'foo/enum.F.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A,'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @matches - '//*[@id="variant.A"]/h3' '^A$'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+pub use bar::F;
+
+// @has 'foo/enum.G.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 12,'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @has - '//*[@class="rust item-decl"]/code' 'C(u32),'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 12$'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+// @has - '//*[@id="variant.C"]/h3' 'C(u32)'
+pub use bar::G;
+
+// @has 'foo/enum.H.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A,'
+// @has - '//*[@class="rust item-decl"]/code' 'C(u32),'
+// @matches - '//*[@id="variant.A"]/h3' '^A$'
+// @has - '//*[@id="variant.C"]/h3' 'C(u32)'
+pub use bar::H;
+
+// Testing more complex cases.
+pub const X: isize = 2;
+// @has 'foo/enum.I.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 2,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 4,'
+// @has - '//*[@class="rust item-decl"]/code' 'C = 9,'
+// @has - '//*[@class="rust item-decl"]/code' 'D = -1,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 2$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 4$'
+// @matches - '//*[@id="variant.C"]/h3' '^C = 9$'
+// @matches - '//*[@id="variant.D"]/h3' '^D = -1$'
+#[repr(isize)]
+pub enum I {
+    A = X,
+    B = X * 2,
+    C = Self::B as isize + X + 3,
+    D = -1,
+}
+
+// Testing `repr`.
+
+// @has 'foo/enum.J.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 0,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 1,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 0$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 1$'
+#[repr(C)]
+pub enum J {
+    A,
+    B,
+}
+
+// @has 'foo/enum.K.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A(u32),'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @has - '//*[@id="variant.A"]/h3' 'A(u32)'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+#[repr(C)]
+pub enum K {
+    A(u32),
+    B,
+}
+
+// @has 'foo/enum.L.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 0,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 1,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 0$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 1$'
+#[repr(u32)]
+pub enum L {
+    A,
+    B,
+}
+
+// @has 'foo/enum.M.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A(u32),'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @has - '//*[@id="variant.A"]/h3' 'A(u32)'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+#[repr(u32)]
+pub enum M {
+    A(u32),
+    B,
+}
+
+// @has 'foo/enum.N.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 0,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 1,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 0$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 1$'
+pub use bar::N;
+
+// @has 'foo/enum.O.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A(u32),'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @has - '//*[@id="variant.A"]/h3' 'A(u32)'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+pub use bar::O;
+
+// @has 'foo/enum.P.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A = 0,'
+// @has - '//*[@class="rust item-decl"]/code' 'B = 1,'
+// @matches - '//*[@id="variant.A"]/h3' '^A = 0$'
+// @matches - '//*[@id="variant.B"]/h3' '^B = 1$'
+pub use bar::P;
+
+// @has 'foo/enum.Q.html'
+// @has - '//*[@class="rust item-decl"]/code' 'A(u32),'
+// @has - '//*[@class="rust item-decl"]/code' 'B,'
+// @has - '//*[@id="variant.A"]/h3' 'A(u32)'
+// @matches - '//*[@id="variant.B"]/h3' '^B$'
+pub use bar::Q;
diff --git a/tests/rustdoc/generic-impl.rs b/tests/rustdoc/generic-impl.rs
index 6f68b157499..f62540c6bf9 100644
--- a/tests/rustdoc/generic-impl.rs
+++ b/tests/rustdoc/generic-impl.rs
@@ -5,9 +5,9 @@ use std::fmt;
 // @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' ''
 pub struct Bar;
 
-// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header"]' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-T"]//h3[@class="code-header"]' 'impl<T> ToString for T'
 pub struct Foo;
-// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString'
+// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-T"]' 'ToString'
 
 impl fmt::Display for Foo {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/tests/rustdoc/inline_cross/auxiliary/const-fn.rs b/tests/rustdoc/inline_cross/auxiliary/const-fn.rs
new file mode 100644
index 00000000000..26332b419b6
--- /dev/null
+++ b/tests/rustdoc/inline_cross/auxiliary/const-fn.rs
@@ -0,0 +1,5 @@
+#![feature(effects)]
+
+pub const fn load() -> i32 {
+    0
+}
diff --git a/tests/rustdoc/inline_cross/const-fn.rs b/tests/rustdoc/inline_cross/const-fn.rs
new file mode 100644
index 00000000000..24934b873c2
--- /dev/null
+++ b/tests/rustdoc/inline_cross/const-fn.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #116629.
+// Check that we render the correct generic params of const fn
+
+// aux-crate:const_fn=const-fn.rs
+// edition: 2021
+#![crate_name = "user"]
+
+// @has user/fn.load.html
+// @has - '//pre[@class="rust item-decl"]' "pub const fn load() -> i32"
+pub use const_fn::load;
diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs
index ac486c36ad0..664b678093e 100644
--- a/tests/rustdoc/issue-32077-type-alias-impls.rs
+++ b/tests/rustdoc/issue-32077-type-alias-impls.rs
@@ -22,7 +22,7 @@ impl Bar for GenericStruct<u32> {}
 // We check that "Aliased type" is also present as a title in the sidebar.
 // @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type'
 // We check that we have the implementation of the type alias itself.
-// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct'
+// @has - '//*[@id="impl-GenericStruct%3Cu8%3E"]/h3' 'impl TypedefStruct'
 // @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()'
 // @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl<T> GenericStruct<T>'
 // @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)'
diff --git a/tests/rustdoc/issue-78701.rs b/tests/rustdoc/issue-78701.rs
index e3e46468f38..3f1638d5ffc 100644
--- a/tests/rustdoc/issue-78701.rs
+++ b/tests/rustdoc/issue-78701.rs
@@ -6,7 +6,7 @@
 
 // @has 'foo/struct.AnotherStruct.html'
 // @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3C()%3E"]' 1
-// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3CT%3E"]' 1
+// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-T"]' 1
 
 pub trait Something {}
 
diff --git a/tests/rustdoc/logo-class-default.rs b/tests/rustdoc/logo-class-default.rs
index d2d4391997f..6b46b46051f 100644
--- a/tests/rustdoc/logo-class-default.rs
+++ b/tests/rustdoc/logo-class-default.rs
@@ -1,4 +1,4 @@
-// Note: this test is paired with logo-class.rs.
-// @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
-// @has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+// Note: this test is paired with logo-class.rs and logo-class-rust.rs.
+// @!has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img' ''
+// @!has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img' ''
 pub struct SomeStruct;
diff --git a/tests/rustdoc/logo-class-rust.rs b/tests/rustdoc/logo-class-rust.rs
new file mode 100644
index 00000000000..d4f6113c0c0
--- /dev/null
+++ b/tests/rustdoc/logo-class-rust.rs
@@ -0,0 +1,7 @@
+#![feature(rustdoc_internals)]
+#![allow(internal_features)]
+#![doc(rust_logo)]
+// Note: this test is paired with logo-class.rs and logo-class-default.rs.
+// @has logo_class_rust/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
+// @has src/logo_class_rust/logo-class-rust.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+pub struct SomeStruct;
diff --git a/tests/rustdoc/logo-class.rs b/tests/rustdoc/logo-class.rs
index d3aa446dab9..d15ce134cd1 100644
--- a/tests/rustdoc/logo-class.rs
+++ b/tests/rustdoc/logo-class.rs
@@ -1,6 +1,6 @@
 #![doc(html_logo_url =
     "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png")]
-// Note: this test is paired with logo-class-default.rs.
+// Note: this test is paired with logo-class-default.rs and logo-class-rust.rs.
 
 // @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
 // @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
diff --git a/tests/rustdoc/primitive/primitive-generic-impl.rs b/tests/rustdoc/primitive/primitive-generic-impl.rs
index 2da8ae6ff38..558336d7316 100644
--- a/tests/rustdoc/primitive/primitive-generic-impl.rs
+++ b/tests/rustdoc/primitive/primitive-generic-impl.rs
@@ -1,7 +1,7 @@
 #![feature(rustc_attrs)]
 #![crate_name = "foo"]
 
-// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header"]' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-T"]//h3[@class="code-header"]' 'impl<T> ToString for T'
 
 #[rustc_doc_primitive = "i32"]
 /// Some useless docs, wouhou!
diff --git a/tests/rustdoc/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar-links-to-foreign-impl.rs
index caa17dfbb1c..733a18ad94a 100644
--- a/tests/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/tests/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -7,8 +7,8 @@
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
 // @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32'
-// @has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26'a+str\"]" "&'a str"
-// @has - "//*[@id=\"impl-Foo-for-%26'a+str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str"
+// @has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26str\"]" "&'a str"
+// @has - "//*[@id=\"impl-Foo-for-%26str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str"
 pub trait Foo {}
 
 impl Foo for u32 {}
diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/src-links-auto-impls.rs
index 1c8d1573192..08a497d4cf5 100644
--- a/tests/rustdoc/src-links-auto-impls.rs
+++ b/tests/rustdoc/src-links-auto-impls.rs
@@ -5,8 +5,8 @@
 // @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'source'
 // @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header"]' 'impl Sync for Unsized'
 // @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'source'
-// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header"]' 'impl<T> Any for T'
-// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="src rightside"]' 'source'
+// @has - '//*[@id="impl-Any-for-T"]/h3[@class="code-header"]' 'impl<T> Any for T'
+// @has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'source'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc/titles.rs
index f6a059de620..f9da5a81375 100644
--- a/tests/rustdoc/titles.rs
+++ b/tests/rustdoc/titles.rs
@@ -2,7 +2,8 @@
 #![feature(rustc_attrs)]
 
 // @matches 'foo/index.html' '//h1' 'Crate foo'
-// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
+// @matches 'foo/index.html' '//div[@class="sidebar-crate"]/h2/a' 'foo'
+// @count 'foo/index.html' '//h2[@class="location"]' 0
 
 // @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
 // @matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
diff --git a/tests/rustdoc/where-clause-order.rs b/tests/rustdoc/where-clause-order.rs
index b10f8f6856e..7261dfa7dd9 100644
--- a/tests/rustdoc/where-clause-order.rs
+++ b/tests/rustdoc/where-clause-order.rs
@@ -7,7 +7,7 @@ where
 }
 
 // @has 'foo/trait.SomeTrait.html'
-// @has - "//*[@id='impl-SomeTrait%3C(A,+B,+C,+D,+E)%3E-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
+// @has - "//*[@id='impl-SomeTrait-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
 impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)
 where
     A: PartialOrd<A> + PartialEq<A>,
@@ -17,3 +17,14 @@ where
     E: PartialOrd<E> + PartialEq<E> + ?Sized,
 {
 }
+
+// @has - "//*[@id='impl-SomeTrait%3C(A,+B,+C,+D)%3E-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
+impl<A, B, C, D, E> SomeTrait<(A, B, C, D)> for (A, B, C, D, E)
+where
+    A: PartialOrd<A> + PartialEq<A>,
+    B: PartialOrd<B> + PartialEq<B>,
+    C: PartialOrd<C> + PartialEq<C>,
+    D: PartialOrd<D> + PartialEq<D>,
+    E: PartialOrd<E> + PartialEq<E> + ?Sized,
+{
+}
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index d482f62ff06..8a812bd3265 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -38,8 +38,8 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
     assert!(get_item(&items, (DefKind::Fn, "foo::bar")).is_some());
 
-    // Find the `std` crate.
-    assert!(stable_mir::find_crate("std").is_some());
+    // Find the `std` crate and assert that there is only one of it.
+    assert!(stable_mir::find_crates("std").len() == 1);
 
     let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap();
     let body = bar.body();
@@ -58,7 +58,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 
     let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap();
     let body = foo_bar.body();
-    assert_eq!(body.locals.len(), 7);
+    assert_eq!(body.locals.len(), 5);
     assert_eq!(body.blocks.len(), 4);
     let block = &body.blocks[0];
     match &block.terminator.kind {
diff --git a/tests/ui/associated-inherent-types/regionck-1.stderr b/tests/ui/associated-inherent-types/regionck-1.stderr
index b17d89ca306..62a00868248 100644
--- a/tests/ui/associated-inherent-types/regionck-1.stderr
+++ b/tests/ui/associated-inherent-types/regionck-1.stderr
@@ -2,9 +2,14 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regionck-1.rs:9:30
    |
 LL |     type NoTyOutliv<'a, T> = &'a T;
-   |                              ^^^^^- help: consider adding a where clause: `where T: 'a`
-   |                              |
-   |                              ...so that the reference type `&'a T` does not outlive the data it points at
+   |                     --       ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+   |                     |
+   |                     the parameter type `T` must be valid for the lifetime `'a` as defined here...
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     type NoTyOutliv<'a, T: 'a> = &'a T;
+   |                          ++++
 
 error[E0491]: in type `&'a &'b ()`, reference has a longer lifetime than the data it references
   --> $DIR/regionck-1.rs:10:31
diff --git a/tests/ui/associated-types/associated-types-coherence-failure.stderr b/tests/ui/associated-types/associated-types-coherence-failure.stderr
index 40c02dca32f..211613b3714 100644
--- a/tests/ui/associated-types/associated-types-coherence-failure.stderr
+++ b/tests/ui/associated-types/associated-types-coherence-failure.stderr
@@ -2,19 +2,19 @@ error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `Co
   --> $DIR/associated-types-coherence-failure.rs:21:1
    |
 LL | impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
-   | ------------------------------------------------------------ first implementation here
+   | ----------------------------------------------------------------------------- first implementation here
 ...
 LL | impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Cow<'_, _>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Cow<'_, _>`
 
 error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `&_`
   --> $DIR/associated-types-coherence-failure.rs:28:1
    |
 LL | impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
-   | ------------------------------------------------------------ first implementation here
+   | ----------------------------------------------------------------------------- first implementation here
 ...
 LL | impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/associated-types/hr-associated-type-bound-2.stderr b/tests/ui/associated-types/hr-associated-type-bound-2.stderr
index 749986f09c6..8ccbc9fb514 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-2.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-2.stderr
@@ -1,8 +1,10 @@
 error[E0275]: overflow evaluating the requirement `for<'b> u32: X<'b>`
   --> $DIR/hr-associated-type-bound-2.rs:11:1
    |
-LL | impl X<'_> for u32
-   | ^^^^^^^^^^^^^^^^^^
+LL | / impl X<'_> for u32
+LL | | where
+LL | |     for<'b> <Self as X<'b>>::U: Clone,
+   | |______________________________________^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`)
 note: required for `u32` to implement `for<'b> X<'b>`
diff --git a/tests/ui/associated-types/impl-wf-cycle-1.stderr b/tests/ui/associated-types/impl-wf-cycle-1.stderr
index 206060f1980..53022dcb4c7 100644
--- a/tests/ui/associated-types/impl-wf-cycle-1.stderr
+++ b/tests/ui/associated-types/impl-wf-cycle-1.stderr
@@ -1,8 +1,12 @@
 error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
   --> $DIR/impl-wf-cycle-1.rs:15:1
    |
-LL | impl<T: Grault> Grault for (T,)
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T: Grault> Grault for (T,)
+LL | |
+LL | | where
+LL | |     Self::A: Baz,
+LL | |     Self::B: Fiz,
+   | |_________________^
    |
 note: required for `(T,)` to implement `Grault`
   --> $DIR/impl-wf-cycle-1.rs:15:17
diff --git a/tests/ui/associated-types/impl-wf-cycle-2.stderr b/tests/ui/associated-types/impl-wf-cycle-2.stderr
index 771ba751e8c..81c58be927e 100644
--- a/tests/ui/associated-types/impl-wf-cycle-2.stderr
+++ b/tests/ui/associated-types/impl-wf-cycle-2.stderr
@@ -1,8 +1,11 @@
 error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
   --> $DIR/impl-wf-cycle-2.rs:7:1
    |
-LL | impl<T: Grault> Grault for (T,)
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T: Grault> Grault for (T,)
+LL | |
+LL | | where
+LL | |     Self::A: Copy,
+   | |__________________^
    |
 note: required for `(T,)` to implement `Grault`
   --> $DIR/impl-wf-cycle-2.rs:7:17
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
index 90b40e221e4..965c385e9bc 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
@@ -2,35 +2,29 @@ error[E0311]: the parameter type `U` may not live long enough
   --> $DIR/async-generics-and-bounds.rs:12:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |            |
+   |     |            the parameter type `U` must be valid for the anonymous lifetime as defined here...
+   |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
-note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
-  --> $DIR/async-generics-and-bounds.rs:12:18
+help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |                  ^
-note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics-and-bounds.rs:12:5
-   |
-LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a;
+   |                 ++++  ++           ++                                       +++++++
 
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/async-generics-and-bounds.rs:12:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |            |
+   |     |            the parameter type `T` must be valid for the anonymous lifetime as defined here...
+   |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
-note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
-  --> $DIR/async-generics-and-bounds.rs:12:18
+help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |                  ^
-note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics-and-bounds.rs:12:5
-   |
-LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a;
+   |                 ++++  ++           ++                                       +++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr
index 07f986e94e0..20c2491e9d0 100644
--- a/tests/ui/async-await/in-trait/async-generics.stderr
+++ b/tests/ui/async-await/in-trait/async-generics.stderr
@@ -2,35 +2,29 @@ error[E0311]: the parameter type `U` may not live long enough
   --> $DIR/async-generics.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
+   |     |            |
+   |     |            the parameter type `U` must be valid for the anonymous lifetime as defined here...
+   |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
-note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
-  --> $DIR/async-generics.rs:9:18
+help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo(&self) -> &(T, U);
-   |                  ^
-note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics.rs:9:5
-   |
-LL |     async fn foo(&self) -> &(T, U);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
+   |                 ++++  ++           ++        +++++++++++
 
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/async-generics.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
+   |     |            |
+   |     |            the parameter type `T` must be valid for the anonymous lifetime as defined here...
+   |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
-note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
-  --> $DIR/async-generics.rs:9:18
+help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo(&self) -> &(T, U);
-   |                  ^
-note: ...so that the reference type `&(T, U)` does not outlive the data it points at
-  --> $DIR/async-generics.rs:9:5
-   |
-LL |     async fn foo(&self) -> &(T, U);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a;
+   |                 ++++  ++           ++        +++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-self-type.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
index e2b177b951c..0e2c6c60b6e 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
@@ -2,14 +2,17 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/builtin-superkinds-self-type.rs:10:16
    |
 LL | impl <T: Sync> Foo for T { }
-   |                ^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |                ^^^
+   |                |
+   |                the parameter type `T` must be valid for the static lifetime...
+   |                ...so that the type `T` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
   --> $DIR/builtin-superkinds-self-type.rs:6:24
    |
 LL | trait Foo : Sized+Sync+'static {
    |                        ^^^^^^^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl <T: Sync + 'static> Foo for T { }
    |               +++++++++
diff --git a/tests/ui/coercion/issue-53475.stderr b/tests/ui/coercion/issue-53475.stderr
index 522c50dca95..4778611bf1b 100644
--- a/tests/ui/coercion/issue-53475.stderr
+++ b/tests/ui/coercion/issue-53475.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue-53475.rs:10:1
    |
 LL | impl<T> CoerceUnsized<Foo<dyn Any>> for Foo<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | the parameter type `T` must be valid for the static lifetime...
+   | ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<T: 'static> CoerceUnsized<Foo<dyn Any>> for Foo<T> {}
    |       +++++++++
diff --git a/tests/ui/coherence/coherence-overlap-downstream.next.stderr b/tests/ui/coherence/coherence-overlap-downstream.next.stderr
index 9d62efbc315..6c2e9466b4b 100644
--- a/tests/ui/coherence/coherence-overlap-downstream.next.stderr
+++ b/tests/ui/coherence/coherence-overlap-downstream.next.stderr
@@ -10,7 +10,7 @@ error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32`
   --> $DIR/coherence-overlap-downstream.rs:17:1
    |
 LL | impl<X, T> Foo<X> for T where T: Bar<X> {}
-   | ----------------------- first implementation here
+   | --------------------------------------- first implementation here
 LL | impl<X> Foo<X> for i32 {}
    | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
    |
diff --git a/tests/ui/coherence/coherence-overlap-downstream.old.stderr b/tests/ui/coherence/coherence-overlap-downstream.old.stderr
index 9d62efbc315..6c2e9466b4b 100644
--- a/tests/ui/coherence/coherence-overlap-downstream.old.stderr
+++ b/tests/ui/coherence/coherence-overlap-downstream.old.stderr
@@ -10,7 +10,7 @@ error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32`
   --> $DIR/coherence-overlap-downstream.rs:17:1
    |
 LL | impl<X, T> Foo<X> for T where T: Bar<X> {}
-   | ----------------------- first implementation here
+   | --------------------------------------- first implementation here
 LL | impl<X> Foo<X> for i32 {}
    | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
    |
diff --git a/tests/ui/coherence/coherence-overlap-upstream.stderr b/tests/ui/coherence/coherence-overlap-upstream.stderr
index f6145c1883a..8272c887586 100644
--- a/tests/ui/coherence/coherence-overlap-upstream.stderr
+++ b/tests/ui/coherence/coherence-overlap-upstream.stderr
@@ -2,7 +2,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `i16`
   --> $DIR/coherence-overlap-upstream.rs:13:1
    |
 LL | impl<T> Foo for T where T: Remote {}
-   | ----------------- first implementation here
+   | --------------------------------- first implementation here
 LL | impl Foo for i16 {}
    | ^^^^^^^^^^^^^^^^ conflicting implementation for `i16`
    |
diff --git a/tests/ui/coherence/coherence-wasm-bindgen.stderr b/tests/ui/coherence/coherence-wasm-bindgen.stderr
index 89615f0fbc6..600cd42d8c6 100644
--- a/tests/ui/coherence/coherence-wasm-bindgen.stderr
+++ b/tests/ui/coherence/coherence-wasm-bindgen.stderr
@@ -1,11 +1,17 @@
 error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn Fn(&_) -> _`
   --> $DIR/coherence-wasm-bindgen.rs:28:1
    |
-LL | impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
-   | ------------------------------------------------------------ first implementation here
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+LL | | where
+LL | |     A: FromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+   | |_____________________- first implementation here
 ...
-LL | impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&dyn Fn(&_) -> _`
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+LL | | where
+LL | |     A: RefFromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+   | |_____________________^ conflicting implementation for `&dyn Fn(&_) -> _`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
diff --git a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr
index 0dd28706e07..9b2dbc66ca7 100644
--- a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr
+++ b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr
@@ -1,11 +1,14 @@
 error[E0119]: conflicting implementations of trait `From<()>` for type `S`
   --> $DIR/inter-crate-ambiguity-causes-notes.rs:12:1
    |
-LL | impl From<()> for S {
-   | ------------------- first implementation here
+LL |   impl From<()> for S {
+   |   ------------------- first implementation here
 ...
-LL | impl<I> From<I> for S
-   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S`
+LL | / impl<I> From<I> for S
+LL | |
+LL | | where
+LL | |     I: Iterator<Item = ()>,
+   | |___________________________^ conflicting implementation for `S`
    |
    = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
 
diff --git a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr
index 0dd28706e07..9b2dbc66ca7 100644
--- a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr
+++ b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr
@@ -1,11 +1,14 @@
 error[E0119]: conflicting implementations of trait `From<()>` for type `S`
   --> $DIR/inter-crate-ambiguity-causes-notes.rs:12:1
    |
-LL | impl From<()> for S {
-   | ------------------- first implementation here
+LL |   impl From<()> for S {
+   |   ------------------- first implementation here
 ...
-LL | impl<I> From<I> for S
-   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S`
+LL | / impl<I> From<I> for S
+LL | |
+LL | | where
+LL | |     I: Iterator<Item = ()>,
+   | |___________________________^ conflicting implementation for `S`
    |
    = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
 
diff --git a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr
index 89289767b83..ecc73d994f9 100644
--- a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr
+++ b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr
@@ -1,11 +1,16 @@
 error: implementations of `PartialEq<Interval<_>>` for `Interval<_>` will conflict in the future
   --> $DIR/warn-when-cycle-is-error-in-coherence.rs:13:1
    |
-LL | #[derive(PartialEq, Default)]
-   |          --------- the second impl is here
+LL |   #[derive(PartialEq, Default)]
+   |            --------- the second impl is here
 ...
-LL | impl<T, Q> PartialEq<Q> for Interval<T>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the first impl is here
+LL | / impl<T, Q> PartialEq<Q> for Interval<T>
+LL | |
+LL | |
+LL | | where
+LL | |     T: Borrow<Q>,
+LL | |     Q: ?Sized + PartialOrd,
+   | |___________________________^ the first impl is here
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #114040 <https://github.com/rust-lang/rust/issues/114040>
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
index 79ed82e02e0..25a455d3308 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
@@ -3,7 +3,7 @@ error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:
 
 Box<dyn Any>
 query stack during panic:
-#0 [eval_to_allocation_raw] const-evaluating + checking `<impl at $DIR/issue-80742.rs:25:1: 25:18>::{constant#0}`
+#0 [eval_to_allocation_raw] const-evaluating + checking `<impl at $DIR/issue-80742.rs:25:1: 27:32>::{constant#0}`
 #1 [eval_to_valtree] evaluating type-level constant
 end of query stack
 error: aborting due to previous error
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
index 8cbd1265448..69bc174b6be 100644
--- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
@@ -7,5 +7,17 @@ LL |         WHAT_A_TYPE => 0,
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: aborting due to previous error
+error[E0015]: cannot match on `TypeId` in constant functions
+  --> $DIR/typeid-equality-by-subtyping.rs:18:9
+   |
+LL |         WHAT_A_TYPE => 0,
+   |         ^^^^^^^^^^^
+   |
+   = note: `TypeId` cannot be compared in compile-time, and therefore cannot be used in `match`es
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.rs b/tests/ui/consts/const-eval/unused-broken-const-late.rs
new file mode 100644
index 00000000000..a6528ec5fd6
--- /dev/null
+++ b/tests/ui/consts/const-eval/unused-broken-const-late.rs
@@ -0,0 +1,20 @@
+// build-fail
+// compile-flags: -O
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct PrintName<T>(T);
+impl<T> PrintName<T> {
+    const VOID: () = panic!(); //~ERROR evaluation of `PrintName::<i32>::VOID` failed
+}
+
+fn no_codegen<T>() {
+    // Any function that is called is guaranteed to have all consts that syntactically
+    // appear in its body evaluated, even if they only appear in dead code.
+    if false {
+        let _ = PrintName::<T>::VOID;
+    }
+}
+pub fn main() {
+    no_codegen::<i32>();
+}
diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.stderr b/tests/ui/consts/const-eval/unused-broken-const-late.stderr
new file mode 100644
index 00000000000..cdb70a69dfd
--- /dev/null
+++ b/tests/ui/consts/const-eval/unused-broken-const-late.stderr
@@ -0,0 +1,11 @@
+error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
+  --> $DIR/unused-broken-const-late.rs:8:22
+   |
+LL |     const VOID: () = panic!();
+   |                      ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unused-broken-const-late.rs:8:22
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs
index 69cf8404da1..88b5d68cb60 100644
--- a/tests/ui/consts/const_in_pattern/issue-78057.rs
+++ b/tests/ui/consts/const_in_pattern/issue-78057.rs
@@ -12,6 +12,5 @@ fn main() {
         FOO => {},
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => {}
-        //~^ ERROR unreachable pattern
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/issue-78057.stderr b/tests/ui/consts/const_in_pattern/issue-78057.stderr
index df155bdb625..5ec68719a97 100644
--- a/tests/ui/consts/const_in_pattern/issue-78057.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-78057.stderr
@@ -7,20 +7,5 @@ LL |         FOO => {},
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: unreachable pattern
-  --> $DIR/issue-78057.rs:14:9
-   |
-LL |         FOO => {},
-   |         --- matches any value
-LL |
-LL |         _ => {}
-   |         ^ unreachable pattern
-   |
-note: the lint level is defined here
-  --> $DIR/issue-78057.rs:1:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/tests/ui/consts/issue-102117.stderr b/tests/ui/consts/issue-102117.stderr
index a297916b30f..da92db87f18 100644
--- a/tests/ui/consts/issue-102117.stderr
+++ b/tests/ui/consts/issue-102117.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue-102117.rs:19:26
    |
 LL |                 type_id: TypeId::of::<T>(),
-   |                          ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |                          ^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          the parameter type `T` must be valid for the static lifetime...
+   |                          ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     pub fn new<T: 'static>() -> &'static Self {
    |                 +++++++++
@@ -13,10 +16,13 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue-102117.rs:19:26
    |
 LL |                 type_id: TypeId::of::<T>(),
-   |                          ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |                          ^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          the parameter type `T` must be valid for the static lifetime...
+   |                          ...so that the type `T` will meet its required lifetime bounds
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     pub fn new<T: 'static>() -> &'static Self {
    |                 +++++++++
diff --git a/tests/ui/consts/issue-67696-const-prop-ice.rs b/tests/ui/consts/issue-67696-const-prop-ice.rs
index ad52608b3f4..858035190ca 100644
--- a/tests/ui/consts/issue-67696-const-prop-ice.rs
+++ b/tests/ui/consts/issue-67696-const-prop-ice.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --emit=mir,link
+// compile-flags: --emit=mir,link -Zmir-opt-level=4
 // Checks that we don't ICE due to attempting to run const prop
 // on a function with unsatisifable 'where' clauses
 
diff --git a/tests/ui/error-codes/E0030-teach.stderr b/tests/ui/error-codes/E0030-teach.stderr
index 3f1ad4af3a9..9435cb204bd 100644
--- a/tests/ui/error-codes/E0030-teach.stderr
+++ b/tests/ui/error-codes/E0030-teach.stderr
@@ -2,7 +2,7 @@ error[E0030]: lower range bound must be less than or equal to upper
   --> $DIR/E0030-teach.rs:5:9
    |
 LL |         1000 ..= 5 => {}
-   |         ^^^^ lower bound larger than upper bound
+   |         ^^^^^^^^^^ lower bound larger than upper bound
    |
    = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
 
diff --git a/tests/ui/error-codes/E0030.stderr b/tests/ui/error-codes/E0030.stderr
index db8161d8fd5..1aeca291678 100644
--- a/tests/ui/error-codes/E0030.stderr
+++ b/tests/ui/error-codes/E0030.stderr
@@ -2,7 +2,7 @@ error[E0030]: lower range bound must be less than or equal to upper
   --> $DIR/E0030.rs:3:9
    |
 LL |         1000 ..= 5 => {}
-   |         ^^^^ lower bound larger than upper bound
+   |         ^^^^^^^^^^ lower bound larger than upper bound
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0311.fixed b/tests/ui/error-codes/E0311.fixed
index 4410a4d707a..09ceecd0666 100644
--- a/tests/ui/error-codes/E0311.fixed
+++ b/tests/ui/error-codes/E0311.fixed
@@ -2,7 +2,7 @@
 
 #![allow(warnings)]
 
-fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
+fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
     with_restriction::<T>(x) //~ ERROR E0311
 }
 
diff --git a/tests/ui/error-codes/E0311.stderr b/tests/ui/error-codes/E0311.stderr
index b0e6dd1e272..96546b83f2f 100644
--- a/tests/ui/error-codes/E0311.stderr
+++ b/tests/ui/error-codes/E0311.stderr
@@ -1,23 +1,15 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/E0311.rs:6:5
    |
-LL |     with_restriction::<T>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/E0311.rs:5:25
-   |
 LL | fn no_restriction<T>(x: &()) -> &() {
-   |                         ^^^
-note: ...so that the type `T` will meet its required lifetime bounds
-  --> $DIR/E0311.rs:6:5
-   |
+   |                         --- the parameter type `T` must be valid for the anonymous lifetime defined here...
 LL |     with_restriction::<T>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
-   |                   +++  ++++      ++
+LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+   |                   +++  ++++      ++         ++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0374.stderr b/tests/ui/error-codes/E0374.stderr
index a7792043067..49ec0bce441 100644
--- a/tests/ui/error-codes/E0374.stderr
+++ b/tests/ui/error-codes/E0374.stderr
@@ -1,8 +1,9 @@
 error[E0374]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
   --> $DIR/E0374.rs:8:1
    |
-LL | impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
+LL | |     where T: CoerceUnsized<U> {}
+   | |_____________________________^
    |
    = note: expected a single field to be coerced, none found
 
diff --git a/tests/ui/error-codes/E0377.stderr b/tests/ui/error-codes/E0377.stderr
index 664e499ec23..9cb11e5a3d3 100644
--- a/tests/ui/error-codes/E0377.stderr
+++ b/tests/ui/error-codes/E0377.stderr
@@ -2,7 +2,7 @@ error[E0377]: the trait `CoerceUnsized` may only be implemented for a coercion b
   --> $DIR/E0377.rs:12:1
    |
 LL | impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: expected coercion between the same definition; expected `Foo`, found `Bar`
 
diff --git a/tests/ui/error-codes/E0476.stderr b/tests/ui/error-codes/E0476.stderr
index a4bb26532a2..0378ac6e8ec 100644
--- a/tests/ui/error-codes/E0476.stderr
+++ b/tests/ui/error-codes/E0476.stderr
@@ -2,7 +2,7 @@ error[E0119]: conflicting implementations of trait `CoerceUnsized<&Wrapper<_>>`
   --> $DIR/E0476.rs:9:1
    |
 LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: conflicting implementation in crate `core`:
            - impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
@@ -12,7 +12,7 @@ error[E0476]: lifetime of the source pointer does not outlive lifetime bound of
   --> $DIR/E0476.rs:9:1
    |
 LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: object type is valid for the lifetime `'a` as defined here
   --> $DIR/E0476.rs:9:6
diff --git a/tests/ui/feature-gates/doc-rust-logo.rs b/tests/ui/feature-gates/doc-rust-logo.rs
new file mode 100644
index 00000000000..e6a58512944
--- /dev/null
+++ b/tests/ui/feature-gates/doc-rust-logo.rs
@@ -0,0 +1,5 @@
+#![doc(rust_logo)]
+//~^ ERROR the `#[doc(rust_logo)]` attribute is used for Rust branding
+//! This is not an official rust crate
+
+fn main() {}
diff --git a/tests/ui/feature-gates/doc-rust-logo.stderr b/tests/ui/feature-gates/doc-rust-logo.stderr
new file mode 100644
index 00000000000..ff5855290d4
--- /dev/null
+++ b/tests/ui/feature-gates/doc-rust-logo.stderr
@@ -0,0 +1,12 @@
+error[E0658]: the `#[doc(rust_logo)]` attribute is used for Rust branding
+  --> $DIR/doc-rust-logo.rs:1:8
+   |
+LL | #![doc(rust_logo)]
+   |        ^^^^^^^^^
+   |
+   = note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
+   = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
index 458756a3dcd..3f6401b9f7a 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
@@ -2,14 +2,16 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:13
    |
 LL | impl<'a, T> Trait<'a> for T {
-   |             ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |      --     ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |      |
+   |      the parameter type `T` must be valid for the lifetime `'a` as defined here...
    |
 note: ...that is required by this bound
   --> $DIR/implied-bounds-unnorm-associated-type-5.rs:1:18
    |
 LL | trait Trait<'a>: 'a {
    |                  ^^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<'a, T: 'a> Trait<'a> for T {
    |           ++++
diff --git a/tests/ui/generic-associated-types/issue-84931.stderr b/tests/ui/generic-associated-types/issue-84931.stderr
index fffea98a449..fe9932c205a 100644
--- a/tests/ui/generic-associated-types/issue-84931.stderr
+++ b/tests/ui/generic-associated-types/issue-84931.stderr
@@ -2,9 +2,14 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-84931.rs:14:21
    |
 LL |     type Item<'a> = &'a mut T;
-   |                     ^^^^^^^^^- help: consider adding a where clause: `where T: 'a`
-   |                     |
-   |                     ...so that the reference type `&'a mut T` does not outlive the data it points at
+   |               --    ^^^^^^^^^ ...so that the reference type `&'a mut T` does not outlive the data it points at
+   |               |
+   |               the parameter type `T` must be valid for the lifetime `'a` as defined here...
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     type Item<'a> = &'a mut T where T: 'a;
+   |                               +++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/impl-trait/in-trait/opaque-variances.rs b/tests/ui/impl-trait/in-trait/opaque-variances.rs
new file mode 100644
index 00000000000..60bfab0deb5
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/opaque-variances.rs
@@ -0,0 +1,14 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Sized {
+    ()
+}
+
+fn main() {
+    // in NLL, we want to make sure that the `'a` subst of `foo` does not get
+    // related between `x` and the RHS of the assignment. That would require
+    // that the temp is live for the lifetime of the variable `x`, which of
+    // course is not necessary since `'a` is not captured by the RPIT.
+    let x = foo(&Vec::new());
+}
diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index 33b48b1e9ea..c60fe08c5d7 100644
--- a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -117,9 +117,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:43:5
    |
 LL |     x
-   |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn ty_param_wont_outlive_static<T:Debug + 'static>(x: T) -> impl Debug + 'static {
    |                                         +++++++++
diff --git a/tests/ui/impl-trait/type_parameters_captured.stderr b/tests/ui/impl-trait/type_parameters_captured.stderr
index fb502cfdd2b..46859296fb8 100644
--- a/tests/ui/impl-trait/type_parameters_captured.stderr
+++ b/tests/ui/impl-trait/type_parameters_captured.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/type_parameters_captured.rs:8:5
    |
 LL |     x
-   |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn foo<T: 'static>(x: T) -> impl Any + 'static {
    |         +++++++++
diff --git a/tests/ui/impl-trait/unactionable_diagnostic.fixed b/tests/ui/impl-trait/unactionable_diagnostic.fixed
index 6c2505177fe..d446512ffc2 100644
--- a/tests/ui/impl-trait/unactionable_diagnostic.fixed
+++ b/tests/ui/impl-trait/unactionable_diagnostic.fixed
@@ -14,7 +14,7 @@ fn foo<'x, P>(
 }
 
 pub fn bar<'t, T: 't>(
-    //~^ HELP: consider adding an explicit lifetime bound...
+    //~^ HELP: consider adding an explicit lifetime bound
     post: T,
     x: &'t Foo,
 ) -> &'t impl Trait {
diff --git a/tests/ui/impl-trait/unactionable_diagnostic.rs b/tests/ui/impl-trait/unactionable_diagnostic.rs
index bce35cbdd0d..76b9a62ca13 100644
--- a/tests/ui/impl-trait/unactionable_diagnostic.rs
+++ b/tests/ui/impl-trait/unactionable_diagnostic.rs
@@ -14,7 +14,7 @@ fn foo<'x, P>(
 }
 
 pub fn bar<'t, T>(
-    //~^ HELP: consider adding an explicit lifetime bound...
+    //~^ HELP: consider adding an explicit lifetime bound
     post: T,
     x: &'t Foo,
 ) -> &'t impl Trait {
diff --git a/tests/ui/impl-trait/unactionable_diagnostic.stderr b/tests/ui/impl-trait/unactionable_diagnostic.stderr
index a32004cda1a..4df7f45c3b3 100644
--- a/tests/ui/impl-trait/unactionable_diagnostic.stderr
+++ b/tests/ui/impl-trait/unactionable_diagnostic.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/unactionable_diagnostic.rs:21:5
    |
+LL | pub fn bar<'t, T>(
+   |            -- the parameter type `T` must be valid for the lifetime `'t` as defined here...
+...
 LL |     foo(post, x)
    |     ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | pub fn bar<'t, T: 't>(
    |                 ++++
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
index 172ee7ade49..168ed37d0e6 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr
+++ b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
@@ -1,16 +1,20 @@
 error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
    |
-LL | impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+LL | | where
+LL | |     T: DispatchFromDyn<U>,
+   | |__________________________^
    |
    = note: extra field `1` of type `i32` is not allowed
 
 error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:21:1
    |
-LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+LL | | where
+LL | |     T: Unsize<U>,
+   | |_________________^
    |
    = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
    = note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`)
@@ -26,14 +30,18 @@ LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingT
 error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:37:1
    |
-LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+LL | | where
+LL | |     T: Unsize<U>,
+   | |_________________^
 
 error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
    |
-LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
+LL | |     where
+LL | |         T: Unsize<U>,
+   | |_____________________^
    |
    = note: extra field `1` of type `OverAlignedZst` is not allowed
 
diff --git a/tests/ui/issues/issue-43355.stderr b/tests/ui/issues/issue-43355.stderr
index 57adc8ad5ef..9aeca8efe4a 100644
--- a/tests/ui/issues/issue-43355.stderr
+++ b/tests/ui/issues/issue-43355.stderr
@@ -2,7 +2,7 @@ error[E0119]: conflicting implementations of trait `Trait1<Box<_>>` for type `A`
   --> $DIR/issue-43355.rs:13:1
    |
 LL | impl<X, T> Trait1<X> for T where T: Trait2<X> {
-   | -------------------------- first implementation here
+   | --------------------------------------------- first implementation here
 ...
 LL | impl<X> Trait1<Box<X>> for A {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A`
diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr
index d6dcc8997b9..dbbe70ff069 100644
--- a/tests/ui/issues/issue-77919.stderr
+++ b/tests/ui/issues/issue-77919.stderr
@@ -27,7 +27,7 @@ LL |     const VAL: T;
    |     ------------ `VAL` from trait
 ...
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
index affb4e8d044..235092e2463 100644
--- a/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
+++ b/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10
    |
 LL |     foo: &'static T
-   |          ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |          ^^^^^^^^^^
+   |          |
+   |          the parameter type `T` must be valid for the static lifetime...
+   |          ...so that the reference type `&'static T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | struct Foo<T: 'static> {
    |             +++++++++
@@ -13,20 +16,24 @@ error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33
    |
 LL |     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
-   |                                 ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |                          --     ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |                          |
+   |                          the parameter type `K` must be valid for the lifetime `'a` as defined here...
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
-LL | impl<K: 'a> Nested<K> {
-   |       ++++
+LL |     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() where K: 'a {
+   |                                                     +++++++++++
 
 error[E0309]: the parameter type `M` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36
    |
 LL |     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
-   |                                    ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
+   |                         --         ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
+   |                         |
+   |                         the parameter type `M` must be valid for the lifetime `'a` as defined here...
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b + 'a>() {
    |                                                            ++++
@@ -35,29 +42,37 @@ error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19
    |
 LL |     fn foo<'a, L: X<&'a Nested<K>>>();
-   |                   ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |            --     ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |            |
+   |            the parameter type `K` must be valid for the lifetime `'a` as defined here...
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
-LL | trait X<K: 'a>: Sized {
-   |          ++++
+LL |     fn foo<'a, L: X<&'a Nested<K>>>() where K: 'a;
+   |                                       +++++++++++
 
 error[E0309]: the parameter type `Self` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19
    |
 LL |     fn bar<'a, L: X<&'a Nested<Self>>>();
-   |                   ^^^^^^^^^^^^^^^^^^^
+   |            --     ^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<Self>` does not outlive the data it points at
+   |            |
+   |            the parameter type `Self` must be valid for the lifetime `'a` as defined here...
    |
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the reference type `&'a Nested<Self>` does not outlive the data it points at
+help: consider adding an explicit lifetime bound
+   |
+LL |     fn bar<'a, L: X<&'a Nested<Self>>>() where Self: 'a;
+   |                                          ++++++++++++++
 
 error[E0309]: the parameter type `L` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22
    |
 LL |     fn baz<'a, L, M: X<&'a Nested<L>>>() {
-   |                      ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
+   |            --        ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
+   |            |
+   |            the parameter type `L` must be valid for the lifetime `'a` as defined here...
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     fn baz<'a, L: 'a, M: X<&'a Nested<L>>>() {
    |                 ++++
diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
index 7049f28e2f6..dbc587dd004 100644
--- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue_74400.rs:12:5
    |
 LL |     f(data, identity)
-   |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn g<T: 'static>(data: &[T]) {
    |       +++++++++
diff --git a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed
index f977f0bd3a8..7c415490439 100644
--- a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed
+++ b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed
@@ -2,7 +2,7 @@
 
 #![allow(warnings)]
 
-fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
+fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
     with_restriction::<T>(x) //~ ERROR the parameter type `T` may not live long enough
 }
 
diff --git a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
index 2d58d3a02f3..79df2c8dfbc 100644
--- a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
+++ b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
@@ -1,23 +1,15 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:6:5
    |
-LL |     with_restriction::<T>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:5:25
-   |
 LL | fn no_restriction<T>(x: &()) -> &() {
-   |                         ^^^
-note: ...so that the type `T` will meet its required lifetime bounds
-  --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:6:5
-   |
+   |                         --- the parameter type `T` must be valid for the anonymous lifetime defined here...
 LL |     with_restriction::<T>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
-   |                   +++  ++++      ++
+LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+   |                   +++  ++++      ++         ++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr b/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr
new file mode 100644
index 00000000000..a5fc96b4e0b
--- /dev/null
+++ b/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr
@@ -0,0 +1,2 @@
+error: some `-C link-self-contained` components were both enabled and disabled: crto, linker
+
diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr b/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr
new file mode 100644
index 00000000000..5982b7a618e
--- /dev/null
+++ b/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr
@@ -0,0 +1,2 @@
+error: some `-C link-self-contained` components were both enabled and disabled: linker
+
diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.rs b/tests/ui/linkage-attr/link-self-contained-consistency.rs
new file mode 100644
index 00000000000..9be72f559a9
--- /dev/null
+++ b/tests/ui/linkage-attr/link-self-contained-consistency.rs
@@ -0,0 +1,10 @@
+// Checks that self-contained linking components cannot be both enabled and disabled at the same
+// time on the CLI.
+
+// check-fail
+// revisions: one many
+// [one] compile-flags: -Clink-self-contained=-linker -Clink-self-contained=+linker -Zunstable-options
+// [many] compile-flags: -Clink-self-contained=+linker,+crto -Clink-self-contained=-linker,-crto -Zunstable-options
+// ignore-tidy-linelength
+
+fn main() {}
diff --git a/tests/ui/linkage-attr/unstable-flavor.bpf.stderr b/tests/ui/linkage-attr/unstable-flavor.bpf.stderr
index 594a461769b..819da2fb017 100644
--- a/tests/ui/linkage-attr/unstable-flavor.bpf.stderr
+++ b/tests/ui/linkage-attr/unstable-flavor.bpf.stderr
@@ -1,2 +1,2 @@
-error: the linker flavor `bpf-linker` is unstable, the `-Z unstable-options` flag must also be passed to use the unstable values
+error: the linker flavor `bpf` is unstable, the `-Z unstable-options` flag must also be passed to use the unstable values
 
diff --git a/tests/ui/linkage-attr/unstable-flavor.ptx.stderr b/tests/ui/linkage-attr/unstable-flavor.ptx.stderr
index 714c09df53f..2ebdc1a9033 100644
--- a/tests/ui/linkage-attr/unstable-flavor.ptx.stderr
+++ b/tests/ui/linkage-attr/unstable-flavor.ptx.stderr
@@ -1,2 +1,2 @@
-error: the linker flavor `ptx-linker` is unstable, the `-Z unstable-options` flag must also be passed to use the unstable values
+error: the linker flavor `ptx` is unstable, the `-Z unstable-options` flag must also be passed to use the unstable values
 
diff --git a/tests/ui/linkage-attr/unstable-flavor.rs b/tests/ui/linkage-attr/unstable-flavor.rs
index b58fd055fdc..c2c16b28bff 100644
--- a/tests/ui/linkage-attr/unstable-flavor.rs
+++ b/tests/ui/linkage-attr/unstable-flavor.rs
@@ -3,11 +3,11 @@
 // caller). If it passes, all the other unstable options are rejected as well.
 //
 // revisions: bpf ptx
-// [bpf] compile-flags: --target=bpfel-unknown-none -C linker-flavor=bpf-linker --crate-type=rlib
-// [bpf] error-pattern: linker flavor `bpf-linker` is unstable, the `-Z unstable-options` flag
+// [bpf] compile-flags: --target=bpfel-unknown-none -C linker-flavor=bpf --crate-type=rlib
+// [bpf] error-pattern: linker flavor `bpf` is unstable, the `-Z unstable-options` flag
 // [bpf] needs-llvm-components:
-// [ptx] compile-flags: --target=nvptx64-nvidia-cuda -C linker-flavor=ptx-linker --crate-type=rlib
-// [ptx] error-pattern: linker flavor `ptx-linker` is unstable, the `-Z unstable-options` flag
+// [ptx] compile-flags: --target=nvptx64-nvidia-cuda -C linker-flavor=ptx --crate-type=rlib
+// [ptx] error-pattern: linker flavor `ptx` is unstable, the `-Z unstable-options` flag
 // [ptx] needs-llvm-components:
 
 #![feature(no_core)]
diff --git a/tests/ui/lint/lint-type-overflow.stderr b/tests/ui/lint/lint-type-overflow.stderr
index 48d8228b802..971c3eb9b2e 100644
--- a/tests/ui/lint/lint-type-overflow.stderr
+++ b/tests/ui/lint/lint-type-overflow.stderr
@@ -29,21 +29,21 @@ LL |     let x1: i8 = 128;
    = help: consider using the type `u8` instead
 
 error: literal out of range for `i8`
-  --> $DIR/lint-type-overflow.rs:18:19
+  --> $DIR/lint-type-overflow.rs:18:18
    |
 LL |     let x3: i8 = -129;
-   |                   ^^^
+   |                  ^^^^
    |
-   = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127`
+   = note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127`
    = help: consider using the type `i16` instead
 
 error: literal out of range for `i8`
-  --> $DIR/lint-type-overflow.rs:19:19
+  --> $DIR/lint-type-overflow.rs:19:18
    |
 LL |     let x3: i8 = -(129);
-   |                   ^^^^^
+   |                  ^^^^^^
    |
-   = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127`
+   = note: the literal `-(129)` does not fit into the type `i8` whose range is `-128..=127`
    = help: consider using the type `i16` instead
 
 error: literal out of range for `i8`
@@ -74,12 +74,12 @@ LL |     let x = 128_i8;
    = help: consider using the type `u8` instead
 
 error: literal out of range for `i8`
-  --> $DIR/lint-type-overflow.rs:28:14
+  --> $DIR/lint-type-overflow.rs:28:13
    |
 LL |     let x = -129_i8;
-   |              ^^^^^^
+   |             ^^^^^^^
    |
-   = note: the literal `129_i8` does not fit into the type `i8` whose range is `-128..=127`
+   = note: the literal `-129_i8` does not fit into the type `i8` whose range is `-128..=127`
    = help: consider using the type `i16` instead
 
 error: literal out of range for `i32`
@@ -101,21 +101,21 @@ LL |     let x = 2147483648_i32;
    = help: consider using the type `u32` instead
 
 error: literal out of range for `i32`
-  --> $DIR/lint-type-overflow.rs:36:19
+  --> $DIR/lint-type-overflow.rs:36:18
    |
 LL |     let x: i32 = -2147483649;
-   |                   ^^^^^^^^^^
+   |                  ^^^^^^^^^^^
    |
-   = note: the literal `2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
+   = note: the literal `-2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
    = help: consider using the type `i64` instead
 
 error: literal out of range for `i32`
-  --> $DIR/lint-type-overflow.rs:37:14
+  --> $DIR/lint-type-overflow.rs:37:13
    |
 LL |     let x = -2147483649_i32;
-   |              ^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^
    |
-   = note: the literal `2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
+   = note: the literal `-2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
    = help: consider using the type `i64` instead
 
 error: literal out of range for `i32`
@@ -146,21 +146,21 @@ LL |     let x = 18446744073709551615_i64;
    = help: consider using the type `u64` instead
 
 error: literal out of range for `i64`
-  --> $DIR/lint-type-overflow.rs:43:19
+  --> $DIR/lint-type-overflow.rs:43:18
    |
 LL |     let x: i64 = -9223372036854775809;
-   |                   ^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807`
+   = note: the literal `-9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807`
    = help: consider using the type `i128` instead
 
 error: literal out of range for `i64`
-  --> $DIR/lint-type-overflow.rs:44:14
+  --> $DIR/lint-type-overflow.rs:44:13
    |
 LL |     let x = -9223372036854775809_i64;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the literal `9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807`
+   = note: the literal `-9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807`
    = help: consider using the type `i128` instead
 
 error: aborting due to 18 previous errors
diff --git a/tests/ui/lint/unaligned_references.rs b/tests/ui/lint/unaligned_references.rs
index 0c9c79c08b2..3f6dab35475 100644
--- a/tests/ui/lint/unaligned_references.rs
+++ b/tests/ui/lint/unaligned_references.rs
@@ -1,3 +1,6 @@
+use std::mem::ManuallyDrop;
+use std::fmt::Debug;
+
 #[repr(packed)]
 pub struct Good {
     data: u64,
@@ -27,6 +30,26 @@ impl Foo for Packed2 {
     }
 }
 
+// Test for #115396
+fn packed_dyn() {
+    #[repr(packed)]
+    struct Unaligned<T: ?Sized>(ManuallyDrop<T>);
+
+    let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u64]));
+    let foo: &Unaligned<dyn Debug> = &*local;
+    println!("{:?}", &*foo.0); //~ ERROR reference to packed field
+    let foo: &Unaligned<[u64]> = &*local;
+    println!("{:?}", &*foo.0); //~ ERROR reference to packed field
+
+    // Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
+    let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u8]));
+    let foo: &Unaligned<dyn Debug> = &*local;
+    println!("{:?}", &*foo.0); //~ ERROR reference to packed field
+    // However, we *can* know the alignment when looking at a slice.
+    let foo: &Unaligned<[u8]> = &*local;
+    println!("{:?}", &*foo.0); // no error!
+}
+
 fn main() {
     unsafe {
         let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
diff --git a/tests/ui/lint/unaligned_references.stderr b/tests/ui/lint/unaligned_references.stderr
index d3abc37669f..328cafbd986 100644
--- a/tests/ui/lint/unaligned_references.stderr
+++ b/tests/ui/lint/unaligned_references.stderr
@@ -1,5 +1,5 @@
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:25:13
+  --> $DIR/unaligned_references.rs:28:13
    |
 LL |             &self.x;
    |             ^^^^^^^
@@ -9,7 +9,37 @@ LL |             &self.x;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:34:17
+  --> $DIR/unaligned_references.rs:40:24
+   |
+LL |     println!("{:?}", &*foo.0);
+   |                        ^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:42:24
+   |
+LL |     println!("{:?}", &*foo.0);
+   |                        ^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:47:24
+   |
+LL |     println!("{:?}", &*foo.0);
+   |                        ^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:57:17
    |
 LL |         let _ = &good.ptr;
    |                 ^^^^^^^^^
@@ -19,7 +49,7 @@ LL |         let _ = &good.ptr;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:35:17
+  --> $DIR/unaligned_references.rs:58:17
    |
 LL |         let _ = &good.data;
    |                 ^^^^^^^^^^
@@ -29,7 +59,7 @@ LL |         let _ = &good.data;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:37:17
+  --> $DIR/unaligned_references.rs:60:17
    |
 LL |         let _ = &good.data as *const _;
    |                 ^^^^^^^^^^
@@ -39,7 +69,7 @@ LL |         let _ = &good.data as *const _;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:38:27
+  --> $DIR/unaligned_references.rs:61:27
    |
 LL |         let _: *const _ = &good.data;
    |                           ^^^^^^^^^^
@@ -49,7 +79,7 @@ LL |         let _: *const _ = &good.data;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:40:17
+  --> $DIR/unaligned_references.rs:63:17
    |
 LL |         let _ = good.data.clone();
    |                 ^^^^^^^^^
@@ -59,7 +89,7 @@ LL |         let _ = good.data.clone();
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:42:17
+  --> $DIR/unaligned_references.rs:65:17
    |
 LL |         let _ = &good.data2[0];
    |                 ^^^^^^^^^^^^^^
@@ -69,7 +99,7 @@ LL |         let _ = &good.data2[0];
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:51:17
+  --> $DIR/unaligned_references.rs:74:17
    |
 LL |         let _ = &packed2.x;
    |                 ^^^^^^^^^^
@@ -79,7 +109,7 @@ LL |         let _ = &packed2.x;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:90:20
+  --> $DIR/unaligned_references.rs:113:20
    |
 LL |         let _ref = &m1.1.a;
    |                    ^^^^^^^
@@ -89,7 +119,7 @@ LL |         let _ref = &m1.1.a;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:93:20
+  --> $DIR/unaligned_references.rs:116:20
    |
 LL |         let _ref = &m2.1.a;
    |                    ^^^^^^^
@@ -98,6 +128,6 @@ LL |         let _ref = &m2.1.a;
    = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0793`.
diff --git a/tests/ui/macros/assert-long-condition.rs b/tests/ui/macros/assert-long-condition.rs
new file mode 100644
index 00000000000..1974ec9d6db
--- /dev/null
+++ b/tests/ui/macros/assert-long-condition.rs
@@ -0,0 +1,9 @@
+// run-fail
+// check-run-results
+// exec-env:RUST_BACKTRACE=0
+// ignore-emscripten no processes
+// ignore-tidy-linelength
+
+fn main() {
+    assert!(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 == 0);
+}
diff --git a/tests/ui/macros/assert-long-condition.run.stderr b/tests/ui/macros/assert-long-condition.run.stderr
new file mode 100644
index 00000000000..16e56c92735
--- /dev/null
+++ b/tests/ui/macros/assert-long-condition.run.stderr
@@ -0,0 +1,4 @@
+thread 'main' panicked at $DIR/assert-long-condition.rs:8:5:
+assertion failed: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18
+                                + 19 + 20 + 21 + 22 + 23 + 24 + 25 == 0
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr b/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr
index e713d1451cf..64bccda56c6 100644
--- a/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr
+++ b/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/overlapping-impl-1-modulo-regions.rs:14:21
    |
 LL | impl<T: Copy> F for T {}
-   |                     ^ ...so that the type `T` will meet its required lifetime bounds
+   |                     ^
+   |                     |
+   |                     the parameter type `T` must be valid for the static lifetime...
+   |                     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<T: Copy + 'static> F for T {}
    |              +++++++++
diff --git a/tests/ui/match/match-range-fail-2.stderr b/tests/ui/match/match-range-fail-2.stderr
index 52a2bf2b34a..089fa851f97 100644
--- a/tests/ui/match/match-range-fail-2.stderr
+++ b/tests/ui/match/match-range-fail-2.stderr
@@ -2,19 +2,19 @@ error[E0030]: lower range bound must be less than or equal to upper
   --> $DIR/match-range-fail-2.rs:5:9
    |
 LL |         6 ..= 1 => { }
-   |         ^ lower bound larger than upper bound
+   |         ^^^^^^^ lower bound larger than upper bound
 
 error[E0579]: lower range bound must be less than upper
   --> $DIR/match-range-fail-2.rs:11:9
    |
 LL |         0 .. 0 => { }
-   |         ^
+   |         ^^^^^^
 
 error[E0030]: lower range bound must be less than or equal to upper
   --> $DIR/match-range-fail-2.rs:17:9
    |
 LL |         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
-   |         ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/match/validate-range-endpoints.rs b/tests/ui/match/validate-range-endpoints.rs
new file mode 100644
index 00000000000..1d1737f8b82
--- /dev/null
+++ b/tests/ui/match/validate-range-endpoints.rs
@@ -0,0 +1,59 @@
+#![feature(exclusive_range_pattern)]
+#![feature(inline_const_pat)]
+#![allow(incomplete_features)]
+#![allow(overlapping_range_endpoints)]
+
+fn main() {
+    const TOO_BIG: u8 = 256;
+    match 0u8 {
+        1..257 => {}
+        //~^ ERROR literal out of range
+        1..=256 => {}
+        //~^ ERROR literal out of range
+
+        // overflow is detected in a later pass for these
+        0..257 => {}
+        0..=256 => {}
+        256..=100 => {}
+
+        // There isn't really a way to detect these
+        1..=TOO_BIG => {}
+        //~^ ERROR lower range bound must be less than or equal to upper
+        1..=const { 256 } => {}
+        //~^ ERROR lower range bound must be less than or equal to upper
+        _ => {}
+    }
+
+    match 0u64 {
+        10000000000000000000..=99999999999999999999 => {}
+        //~^ ERROR literal out of range
+        _ => {}
+    }
+
+    match 0i8 {
+        0..129 => {}
+        //~^ ERROR literal out of range
+        0..=128 => {}
+        //~^ ERROR literal out of range
+        -129..0 => {}
+        //~^ ERROR literal out of range
+        -10000..=-20 => {}
+        //~^ ERROR literal out of range
+
+        // overflow is detected in a later pass for these
+        128..=0 => {}
+        0..-129 => {}
+        -10000..=0 => {}
+        _ => {}
+    }
+
+    // FIXME: error message is confusing
+    match 0i8 {
+        //~^ ERROR `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered
+        -10000..=0 => {}
+    }
+    match 0i8 {
+        //~^ ERROR `i8::MIN..=-17_i8` not covered
+        -10000.. => {}
+    }
+}
diff --git a/tests/ui/match/validate-range-endpoints.stderr b/tests/ui/match/validate-range-endpoints.stderr
new file mode 100644
index 00000000000..0813fccff51
--- /dev/null
+++ b/tests/ui/match/validate-range-endpoints.stderr
@@ -0,0 +1,84 @@
+error: literal out of range for `u8`
+  --> $DIR/validate-range-endpoints.rs:9:12
+   |
+LL |         1..257 => {}
+   |            ^^^ this value does not fit into the type `u8` whose range is `0..=255`
+
+error: literal out of range for `u8`
+  --> $DIR/validate-range-endpoints.rs:11:13
+   |
+LL |         1..=256 => {}
+   |             ^^^ this value does not fit into the type `u8` whose range is `0..=255`
+
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/validate-range-endpoints.rs:20:9
+   |
+LL |         1..=TOO_BIG => {}
+   |         ^^^^^^^^^^^ lower bound larger than upper bound
+
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/validate-range-endpoints.rs:22:9
+   |
+LL |         1..=const { 256 } => {}
+   |         ^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
+
+error: literal out of range for `u64`
+  --> $DIR/validate-range-endpoints.rs:28:32
+   |
+LL |         10000000000000000000..=99999999999999999999 => {}
+   |                                ^^^^^^^^^^^^^^^^^^^^ this value does not fit into the type `u64` whose range is `0..=18446744073709551615`
+
+error: literal out of range for `i8`
+  --> $DIR/validate-range-endpoints.rs:34:12
+   |
+LL |         0..129 => {}
+   |            ^^^ this value does not fit into the type `i8` whose range is `-128..=127`
+
+error: literal out of range for `i8`
+  --> $DIR/validate-range-endpoints.rs:36:13
+   |
+LL |         0..=128 => {}
+   |             ^^^ this value does not fit into the type `i8` whose range is `-128..=127`
+
+error: literal out of range for `i8`
+  --> $DIR/validate-range-endpoints.rs:38:9
+   |
+LL |         -129..0 => {}
+   |         ^^^^ this value does not fit into the type `i8` whose range is `-128..=127`
+
+error: literal out of range for `i8`
+  --> $DIR/validate-range-endpoints.rs:40:9
+   |
+LL |         -10000..=-20 => {}
+   |         ^^^^^^ this value does not fit into the type `i8` whose range is `-128..=127`
+
+error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered
+  --> $DIR/validate-range-endpoints.rs:51:11
+   |
+LL |     match 0i8 {
+   |           ^^^ patterns `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         -10000..=0 => {},
+LL +         i8::MIN..=-17_i8 | 1_i8..=i8::MAX => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` not covered
+  --> $DIR/validate-range-endpoints.rs:55:11
+   |
+LL |     match 0i8 {
+   |           ^^^ pattern `i8::MIN..=-17_i8` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         -10000.. => {},
+LL +         i8::MIN..=-17_i8 => todo!()
+   |
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0004, E0030.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/never_type/never-from-impl-is-reserved.stderr b/tests/ui/never_type/never-from-impl-is-reserved.stderr
index f9f7c787ecb..871c5120528 100644
--- a/tests/ui/never_type/never-from-impl-is-reserved.stderr
+++ b/tests/ui/never_type/never-from-impl-is-reserved.stderr
@@ -5,7 +5,7 @@ LL | impl MyTrait for MyFoo {}
    | ---------------------- first implementation here
 LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
 LL | impl<T> MyTrait for T where T: From<!> {}
-   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
    |
    = note: permitting this impl would forbid us from adding `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details
 
diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
index 1aa7de1e137..a20f885fe81 100644
--- a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -25,10 +25,13 @@ LL | |     T: Trait<'a>,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/propagate-from-trait-match.rs:43:9
    |
+LL | fn supply<'a, T>(value: T)
+   |           -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |         require(value);
    |         ^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: Trait<'a> + 'a,
    |                  ++++
diff --git a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
index d8b26f0b017..4e741abc2dc 100644
--- a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
+++ b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
@@ -37,10 +37,12 @@ LL |     || { None::<&'a &'b ()>; };
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-98589-closures-relate-named-regions.rs:26:10
    |
+LL | fn test_early_type<'a: 'a, T>() {
+   |                    -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     || { None::<&'a T>; };
    |          ^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test_early_type<'a: 'a, T: 'a>() {
    |                             ++++
@@ -48,10 +50,12 @@ LL | fn test_early_type<'a: 'a, T: 'a>() {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-98589-closures-relate-named-regions.rs:32:10
    |
+LL | fn test_late_type<'a, T>() {
+   |                   -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     || { None::<&'a T>; };
    |          ^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test_late_type<'a, T: 'a>() {
    |                        ++++
diff --git a/tests/ui/nll/issue-98693.stderr b/tests/ui/nll/issue-98693.stderr
index 15ca38aa25d..a3d87d74a8e 100644
--- a/tests/ui/nll/issue-98693.stderr
+++ b/tests/ui/nll/issue-98693.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue-98693.rs:16:9
    |
 LL |         assert_static::<T>();
-   |         ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         the parameter type `T` must be valid for the static lifetime...
+   |         ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test<T: 'static>() {
    |          +++++++++
diff --git a/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr b/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr
index e0d476a33b2..cab75e630a7 100644
--- a/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr
+++ b/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/min-choice-reject-ambiguous.rs:17:5
    |
+LL | fn test_b<'a, 'b, 'c, T>() -> impl Cap<'a> + Cap<'b> + Cap<'c>
+   |           -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     type_test::<'_, T>() // This should pass if we pick 'b.
    |     ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: 'b + 'a,
    |           ++++
@@ -12,10 +15,13 @@ LL |     T: 'b + 'a,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/min-choice-reject-ambiguous.rs:28:5
    |
+LL | fn test_c<'a, 'b, 'c, T>() -> impl Cap<'a> + Cap<'b> + Cap<'c>
+   |           -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     type_test::<'_, T>() // This should pass if we pick 'c.
    |     ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: 'c + 'a,
    |           ++++
diff --git a/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr b/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr
index 64b08a9b32f..ff9d750570e 100644
--- a/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr
+++ b/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:11:5
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+   |              -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: Debug + 'a,
    |              ++++
@@ -12,10 +15,13 @@ LL |     T: Debug + 'a,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:26:5
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+   |                 -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: 'b + Debug + 'a,
    |                   ++++
diff --git a/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr b/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr
index d949e29b2b8..6de023ffdd4 100644
--- a/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr
+++ b/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/projection-implied-bounds.rs:30:36
    |
 LL |     twice(value, |value_ref, item| invoke2(value_ref, item));
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    the parameter type `T` must be valid for the static lifetime...
+   |                                    ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn generic2<T: Iterator + 'static>(value: T) {
    |                         +++++++++
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
index 433024c30bb..4f93fb4eaea 100644
--- a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -25,11 +25,16 @@ LL | |     T: Iterator,
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-closure.rs:25:31
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+   |              -- the associated type `<T as Iterator>::Item` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(x, |mut y| Box::new(y.next()))
-   |                               ^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^ ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
-   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound
+   |
+LL |     T: Iterator, <T as Iterator>::Item: 'a
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 note: external requirements
   --> $DIR/projection-no-regions-closure.rs:34:23
@@ -82,11 +87,16 @@ LL | |     T: 'b + Iterator,
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-closure.rs:42:31
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+   |                 -- the associated type `<T as Iterator>::Item` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(x, |mut y| Box::new(y.next()))
-   |                               ^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^ ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-   = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
-   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+LL |     T: 'b + Iterator, <T as Iterator>::Item: 'a
+   |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 note: external requirements
   --> $DIR/projection-no-regions-closure.rs:52:23
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr
index e0ff544fe47..da76ac1c474 100644
--- a/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr
@@ -1,20 +1,30 @@
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-fn.rs:13:5
    |
+LL | fn no_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
+   |              -- the associated type `<T as Iterator>::Item` must be valid for the lifetime `'a` as defined here...
+...
 LL |     Box::new(x.next())
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
-   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound
+   |
+LL |     T: Iterator, <T as Iterator>::Item: 'a
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-fn.rs:28:5
    |
+LL | fn wrong_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
+   |                 -- the associated type `<T as Iterator>::Item` must be valid for the lifetime `'a` as defined here...
+...
 LL |     Box::new(x.next())
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-   = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
-   = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+LL |     T: 'b + Iterator, <T as Iterator>::Item: 'a
+   |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
index ebdce7bc108..dda60398198 100644
--- a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -27,10 +27,13 @@ LL | |     T: Anything<'b>,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:39
    |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+   |                          -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                                       ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: Anything<'b> + 'a,
    |                     ++++
@@ -77,10 +80,13 @@ LL | |     'a: 'a,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:39
    |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+   |                           -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                                       ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: Anything<'b> + 'a,
    |                     ++++
diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index dbad8e47846..c157e89ff8f 100644
--- a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -26,11 +26,13 @@ LL | |     T: Anything<'b, 'c>,
 error[E0309]: the associated type `<T as Anything<'?5, '?6>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:38:39
    |
+LL | fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+   |                          -- the associated type `<T as Anything<'?5, '?6>>::AssocType` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                                       ^^^^^^^^^^^^^^^^
+   |                                       ^^^^^^^^^^^^^^^^ ...so that the type `<T as Anything<'?5, '?6>>::AssocType` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<T as Anything<'?5, '?6>>::AssocType: 'a`...
-   = note: ...so that the type `<T as Anything<'?5, '?6>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
@@ -60,11 +62,13 @@ LL | |     'a: 'a,
 error[E0309]: the associated type `<T as Anything<'?6, '?7>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:39
    |
+LL | fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+   |                           -- the associated type `<T as Anything<'?6, '?7>>::AssocType` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                                       ^^^^^^^^^^^^^^^^
+   |                                       ^^^^^^^^^^^^^^^^ ...so that the type `<T as Anything<'?6, '?7>>::AssocType` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<T as Anything<'?6, '?7>>::AssocType: 'a`...
-   = note: ...so that the type `<T as Anything<'?6, '?7>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
index b4435fe06bc..1fa74f67ccd 100644
--- a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
@@ -1,11 +1,13 @@
 error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
   --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5
    |
+LL | fn foo1<'a, 'b, T>() -> &'a ()
+   |         -- the associated type `<T as MyTrait<'_>>::Output` must be valid for the lifetime `'a` as defined here...
+...
 LL |     bar::<T::Output>()
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
-   = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
index ddeaf3c1f9e..c8dbe4ebc6d 100644
--- a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
@@ -1,11 +1,13 @@
 error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
   --> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
    |
+LL | fn foo1<'a, 'b, T>() -> &'a ()
+   |         -- the associated type `<T as MyTrait<'_>>::Output` must be valid for the lifetime `'a` as defined here...
+...
 LL |     bar::<<T as MyTrait<'a>>::Output>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
-   = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr b/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr
index 0df44644d6a..f78708dc48d 100644
--- a/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-where-clause-none.rs:14:5
    |
+LL | fn foo<'a, T>() -> &'a ()
+   |        -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     bar::<T::Output>()
    |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: MyTrait<'a> + 'a,
    |                    ++++
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index f58d49d8461..59e29e9a420 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -46,10 +46,12 @@ LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:31
    |
+LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+   |                 -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     twice(cell, value, |a, b| invoke(a, b));
    |                               ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn generic_fail<'a, T: 'a>(cell: Cell<&'a ()>, value: T) {
    |                      ++++
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
index ddad1d205e7..3468c5ad372 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -25,10 +25,13 @@ LL | |     T: Debug,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:27
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+   |              -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     with_signature(x, |y| y)
    |                           ^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: Debug + 'a,
    |              ++++
@@ -36,10 +39,13 @@ LL |     T: Debug + 'a,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+   |                 -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: 'b + Debug + 'a,
    |                   ++++
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
index bb455e9aed0..cef4a0f1e93 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -24,10 +24,13 @@ LL | fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:32:9
    |
+LL | fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
+   |              -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |         require(&x, &y)
    |         ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) {
    |                   ++++
@@ -84,10 +87,13 @@ LL | |     T: 'b,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:65:9
    |
+LL | fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+   |                 -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |         require(&x, &y)
    |         ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: 'b + 'a,
    |           ++++
diff --git a/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr b/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr
index 5fb69255dba..73f01ff1519 100644
--- a/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn-body.rs:17:5
    |
+LL | fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
+   |                  -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     outlives(cell, t)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn region_static<'a, T: 'a>(cell: Cell<&'a usize>, t: T) {
    |                       ++++
diff --git a/tests/ui/nll/ty-outlives/ty-param-fn.stderr b/tests/ui/nll/ty-outlives/ty-param-fn.stderr
index 825b26d2f77..56bd41051e2 100644
--- a/tests/ui/nll/ty-outlives/ty-param-fn.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-fn.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:9:5
    |
+LL | fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+   |              -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: Debug + 'a,
    |              ++++
@@ -12,10 +15,13 @@ LL |     T: Debug + 'a,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:24:5
    |
+LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+   |                 -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     T: 'b + Debug + 'a,
    |                   ++++
diff --git a/tests/ui/nll/user-annotations/normalization-infer.stderr b/tests/ui/nll/user-annotations/normalization-infer.stderr
index 12854ab6816..41d563a5523 100644
--- a/tests/ui/nll/user-annotations/normalization-infer.stderr
+++ b/tests/ui/nll/user-annotations/normalization-infer.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/normalization-infer.rs:11:12
    |
 LL |     let _: <(_,) as Tr>::Ty = a;
-   |            ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |            ^^^^^^^^^^^^^^^^
+   |            |
+   |            the parameter type `A` must be valid for the static lifetime...
+   |            ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test1<A: 'static, B, C, D>(a: A, b: B, c: C) {
    |           +++++++++
@@ -13,9 +16,12 @@ error[E0310]: the parameter type `B` may not live long enough
   --> $DIR/normalization-infer.rs:12:5
    |
 LL |     Some::<<(_,) as Tr>::Ty>(b);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `B` must be valid for the static lifetime...
+   |     ...so that the type `B` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test1<A, B: 'static, C, D>(a: A, b: B, c: C) {
    |              +++++++++
@@ -24,9 +30,12 @@ error[E0310]: the parameter type `C` may not live long enough
   --> $DIR/normalization-infer.rs:13:11
    |
 LL |     || -> <(_,) as Tr>::Ty { c };
-   |           ^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |           ^^^^^^^^^^^^^^^^
+   |           |
+   |           the parameter type `C` must be valid for the static lifetime...
+   |           ...so that the type `C` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test1<A, B, C: 'static, D>(a: A, b: B, c: C) {
    |                 +++++++++
@@ -35,9 +44,12 @@ error[E0310]: the parameter type `D` may not live long enough
   --> $DIR/normalization-infer.rs:14:6
    |
 LL |     |d: <(_,) as Tr>::Ty| -> D { d };
-   |      ^ ...so that the type `D` will meet its required lifetime bounds
+   |      ^
+   |      |
+   |      the parameter type `D` must be valid for the static lifetime...
+   |      ...so that the type `D` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test1<A, B, C, D: 'static>(a: A, b: B, c: C) {
    |                    +++++++++
@@ -46,9 +58,12 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/normalization-infer.rs:28:12
    |
 LL |     let _: Alias<_, _> = (a, 0u8);
-   |            ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |            ^^^^^^^^^^^
+   |            |
+   |            the parameter type `A` must be valid for the static lifetime...
+   |            ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test2<A: 'static, B, C>(a: A, b: B, c: C) {
    |           +++++++++
@@ -57,9 +72,12 @@ error[E0310]: the parameter type `B` may not live long enough
   --> $DIR/normalization-infer.rs:29:5
    |
 LL |     Some::<Alias<_, _>>((b, 0u8));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `B` must be valid for the static lifetime...
+   |     ...so that the type `B` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test2<A, B: 'static, C>(a: A, b: B, c: C) {
    |              +++++++++
@@ -68,9 +86,12 @@ error[E0310]: the parameter type `C` may not live long enough
   --> $DIR/normalization-infer.rs:30:11
    |
 LL |     || -> Alias<_, _> { (c, 0u8) };
-   |           ^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |           ^^^^^^^^^^^
+   |           |
+   |           the parameter type `C` must be valid for the static lifetime...
+   |           ...so that the type `C` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn test2<A, B, C: 'static>(a: A, b: B, c: C) {
    |                 +++++++++
diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr b/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr
index 40429fe756f..2d2bb27b8f3 100644
--- a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr
+++ b/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr
@@ -1,17 +1,11 @@
 error[E0311]: the parameter type `Self` may not live long enough
    |
-note: the parameter type `Self` must be valid for the lifetime `'a` as defined here...
-  --> $DIR/object-safety-supertrait-mentions-GAT.rs:9:26
-   |
-LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
-   |                          ^^
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the type `Self` will meet its required lifetime bounds...
 note: ...that is required by this bound
   --> $DIR/object-safety-supertrait-mentions-GAT.rs:6:15
    |
 LL |         Self: 'a;
    |               ^^
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
 
 error: associated item referring to unboxed trait object for its own trait
   --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
diff --git a/tests/ui/parser/attr-bad-meta-2.rs b/tests/ui/parser/attribute/attr-bad-meta-2.rs
index db612ed883d..db612ed883d 100644
--- a/tests/ui/parser/attr-bad-meta-2.rs
+++ b/tests/ui/parser/attribute/attr-bad-meta-2.rs
diff --git a/tests/ui/parser/attr-bad-meta-2.stderr b/tests/ui/parser/attribute/attr-bad-meta-2.stderr
index 6fc6fb665a8..6fc6fb665a8 100644
--- a/tests/ui/parser/attr-bad-meta-2.stderr
+++ b/tests/ui/parser/attribute/attr-bad-meta-2.stderr
diff --git a/tests/ui/parser/attr-bad-meta-3.rs b/tests/ui/parser/attribute/attr-bad-meta-3.rs
index b51e9f2212d..b51e9f2212d 100644
--- a/tests/ui/parser/attr-bad-meta-3.rs
+++ b/tests/ui/parser/attribute/attr-bad-meta-3.rs
diff --git a/tests/ui/parser/attr-bad-meta-3.stderr b/tests/ui/parser/attribute/attr-bad-meta-3.stderr
index 4fa420c79fc..4fa420c79fc 100644
--- a/tests/ui/parser/attr-bad-meta-3.stderr
+++ b/tests/ui/parser/attribute/attr-bad-meta-3.stderr
diff --git a/tests/ui/parser/attr-bad-meta.rs b/tests/ui/parser/attribute/attr-bad-meta.rs
index 8001977f5a3..8001977f5a3 100644
--- a/tests/ui/parser/attr-bad-meta.rs
+++ b/tests/ui/parser/attribute/attr-bad-meta.rs
diff --git a/tests/ui/parser/attr-bad-meta.stderr b/tests/ui/parser/attribute/attr-bad-meta.stderr
index 8d65c423c8d..8d65c423c8d 100644
--- a/tests/ui/parser/attr-bad-meta.stderr
+++ b/tests/ui/parser/attribute/attr-bad-meta.stderr
diff --git a/tests/ui/parser/attr-before-eof.rs b/tests/ui/parser/attribute/attr-before-eof.rs
index 6af1783e630..6af1783e630 100644
--- a/tests/ui/parser/attr-before-eof.rs
+++ b/tests/ui/parser/attribute/attr-before-eof.rs
diff --git a/tests/ui/parser/attr-before-eof.stderr b/tests/ui/parser/attribute/attr-before-eof.stderr
index a2acb94372b..a2acb94372b 100644
--- a/tests/ui/parser/attr-before-eof.stderr
+++ b/tests/ui/parser/attribute/attr-before-eof.stderr
diff --git a/tests/ui/parser/attr-dangling-in-fn.rs b/tests/ui/parser/attribute/attr-dangling-in-fn.rs
index c7c45bafb0d..c7c45bafb0d 100644
--- a/tests/ui/parser/attr-dangling-in-fn.rs
+++ b/tests/ui/parser/attribute/attr-dangling-in-fn.rs
diff --git a/tests/ui/parser/attr-dangling-in-fn.stderr b/tests/ui/parser/attribute/attr-dangling-in-fn.stderr
index b1bb3ab3b17..b1bb3ab3b17 100644
--- a/tests/ui/parser/attr-dangling-in-fn.stderr
+++ b/tests/ui/parser/attribute/attr-dangling-in-fn.stderr
diff --git a/tests/ui/parser/attr-dangling-in-mod.rs b/tests/ui/parser/attribute/attr-dangling-in-mod.rs
index 261ed3913af..261ed3913af 100644
--- a/tests/ui/parser/attr-dangling-in-mod.rs
+++ b/tests/ui/parser/attribute/attr-dangling-in-mod.rs
diff --git a/tests/ui/parser/attr-dangling-in-mod.stderr b/tests/ui/parser/attribute/attr-dangling-in-mod.stderr
index 1c892eac08f..1c892eac08f 100644
--- a/tests/ui/parser/attr-dangling-in-mod.stderr
+++ b/tests/ui/parser/attribute/attr-dangling-in-mod.stderr
diff --git a/tests/ui/parser/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
index d1950087c4c..d1950087c4c 100644
--- a/tests/ui/parser/attr-stmt-expr-attr-bad.rs
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
diff --git a/tests/ui/parser/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
index e46c591080d..e46c591080d 100644
--- a/tests/ui/parser/attr-stmt-expr-attr-bad.stderr
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
diff --git a/tests/ui/parser/attr-with-a-semicolon.rs b/tests/ui/parser/attribute/attr-with-a-semicolon.rs
index 56fe40b916b..56fe40b916b 100644
--- a/tests/ui/parser/attr-with-a-semicolon.rs
+++ b/tests/ui/parser/attribute/attr-with-a-semicolon.rs
diff --git a/tests/ui/parser/attr-with-a-semicolon.stderr b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr
index 0de3490b8ea..0de3490b8ea 100644
--- a/tests/ui/parser/attr-with-a-semicolon.stderr
+++ b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr
diff --git a/tests/ui/parser/attr.rs b/tests/ui/parser/attribute/attr.rs
index 42b2dfde855..42b2dfde855 100644
--- a/tests/ui/parser/attr.rs
+++ b/tests/ui/parser/attribute/attr.rs
diff --git a/tests/ui/parser/attr.stderr b/tests/ui/parser/attribute/attr.stderr
index 7cd0ac2244a..7cd0ac2244a 100644
--- a/tests/ui/parser/attr.stderr
+++ b/tests/ui/parser/attribute/attr.stderr
diff --git a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.rs b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.rs
index c2cc91d8f77..c2cc91d8f77 100644
--- a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.rs
+++ b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.rs
diff --git a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.stderr b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.stderr
index 4c5964715db..4c5964715db 100644
--- a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.stderr
+++ b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.stderr
diff --git a/tests/ui/parser/attrs-after-extern-mod.rs b/tests/ui/parser/attribute/attrs-after-extern-mod.rs
index e3f0fa0fc46..e3f0fa0fc46 100644
--- a/tests/ui/parser/attrs-after-extern-mod.rs
+++ b/tests/ui/parser/attribute/attrs-after-extern-mod.rs
diff --git a/tests/ui/parser/attrs-after-extern-mod.stderr b/tests/ui/parser/attribute/attrs-after-extern-mod.stderr
index 135d98457e1..135d98457e1 100644
--- a/tests/ui/parser/attrs-after-extern-mod.stderr
+++ b/tests/ui/parser/attribute/attrs-after-extern-mod.stderr
diff --git a/tests/ui/parser/break-in-unlabeled-block-in-macro.rs b/tests/ui/parser/break-in-unlabeled-block-in-macro.rs
new file mode 100644
index 00000000000..eecc0026b12
--- /dev/null
+++ b/tests/ui/parser/break-in-unlabeled-block-in-macro.rs
@@ -0,0 +1,43 @@
+macro_rules! foo {
+    () => {
+        break (); //~ ERROR `break` outside of a loop or labeled block
+    };
+    ($e: expr) => {
+        break $e; //~ ERROR `break` outside of a loop or labeled block
+    };
+    (stmt $s: stmt) => {
+        $s
+    };
+    (@ $e: expr) => {
+        { break $e; } //~ ERROR `break` outside of a loop or labeled block
+    };
+    (=> $s: stmt) => {
+        { $s }
+    };
+}
+
+fn main() {
+    {
+        foo!();
+    }
+    {
+        foo!(());
+    }
+    {
+        foo!(stmt break ()); //~ ERROR `break` outside of a loop or labeled block
+    }
+    {
+        foo!(@ ());
+    }
+    {
+        foo!(=> break ()); //~ ERROR `break` outside of a loop or labeled block
+    }
+    {
+        macro_rules! bar {
+            () => {
+                break () //~ ERROR `break` outside of a loop or labeled block
+            };
+        }
+        bar!()
+    }
+}
diff --git a/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr b/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr
new file mode 100644
index 00000000000..9407e8ac002
--- /dev/null
+++ b/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr
@@ -0,0 +1,69 @@
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block-in-macro.rs:3:9
+   |
+LL |         break ();
+   |         ^^^^^^^^ cannot `break` outside of a loop or labeled block
+...
+LL |         foo!();
+   |         ------ in this macro invocation
+   |
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block-in-macro.rs:6:9
+   |
+LL |         break $e;
+   |         ^^^^^^^^ cannot `break` outside of a loop or labeled block
+...
+LL |         foo!(());
+   |         -------- in this macro invocation
+   |
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block-in-macro.rs:27:19
+   |
+LL |         foo!(stmt break ());
+   |                   ^^^^^^^^ cannot `break` outside of a loop or labeled block
+   |
+help: consider labeling this block to be able to break within it
+   |
+LL ~     'block: {
+LL ~         foo!(stmt break 'block ());
+   |
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block-in-macro.rs:12:11
+   |
+LL |         { break $e; }
+   |           ^^^^^^^^ cannot `break` outside of a loop or labeled block
+...
+LL |         foo!(@ ());
+   |         ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider labeling this block to be able to break within it
+   |
+LL |         'block: { break 'block $e; }
+   |         +++++++         ++++++
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block-in-macro.rs:33:17
+   |
+LL |         foo!(=> break ());
+   |                 ^^^^^^^^ cannot `break` outside of a loop or labeled block
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block-in-macro.rs:38:17
+   |
+LL |                 break ()
+   |                 ^^^^^^^^ cannot `break` outside of a loop or labeled block
+...
+LL |         bar!()
+   |         ------ in this macro invocation
+   |
+   = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0268`.
diff --git a/tests/ui/parser/break-in-unlabeled-block.fixed b/tests/ui/parser/break-in-unlabeled-block.fixed
new file mode 100644
index 00000000000..08856232521
--- /dev/null
+++ b/tests/ui/parser/break-in-unlabeled-block.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+fn main() {
+    'block: {
+        break 'block (); //~ ERROR `break` outside of a loop or labeled block
+    }
+    {
+        'block: {
+            break 'block (); //~ ERROR `break` outside of a loop or labeled block
+        }
+    }
+}
diff --git a/tests/ui/parser/break-in-unlabeled-block.rs b/tests/ui/parser/break-in-unlabeled-block.rs
new file mode 100644
index 00000000000..3e5587e9f9c
--- /dev/null
+++ b/tests/ui/parser/break-in-unlabeled-block.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+fn main() {
+    {
+        break (); //~ ERROR `break` outside of a loop or labeled block
+    }
+    {
+        {
+            break (); //~ ERROR `break` outside of a loop or labeled block
+        }
+    }
+}
diff --git a/tests/ui/parser/break-in-unlabeled-block.stderr b/tests/ui/parser/break-in-unlabeled-block.stderr
new file mode 100644
index 00000000000..632cca80d8c
--- /dev/null
+++ b/tests/ui/parser/break-in-unlabeled-block.stderr
@@ -0,0 +1,27 @@
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block.rs:4:9
+   |
+LL |         break ();
+   |         ^^^^^^^^ cannot `break` outside of a loop or labeled block
+   |
+help: consider labeling this block to be able to break within it
+   |
+LL ~     'block: {
+LL ~         break 'block ();
+   |
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-in-unlabeled-block.rs:8:13
+   |
+LL |             break ();
+   |             ^^^^^^^^ cannot `break` outside of a loop or labeled block
+   |
+help: consider labeling this block to be able to break within it
+   |
+LL ~         'block: {
+LL ~             break 'block ();
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0268`.
diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs
index 5c331547366..fc52ee3d013 100644
--- a/tests/ui/pattern/non-structural-match-types.rs
+++ b/tests/ui/pattern/non-structural-match-types.rs
@@ -6,9 +6,9 @@
 
 fn main() {
     match loop {} {
-        const { || {} } => {}, //~ ERROR cannot be used in patterns
+        const { || {} } => {} //~ ERROR cannot be used in patterns
     }
     match loop {} {
-        const { async {} } => {}, //~ ERROR cannot be used in patterns
+        const { async {} } => {} //~ ERROR cannot be used in patterns
     }
 }
diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr
index 43d92775e88..f3e0665fef5 100644
--- a/tests/ui/pattern/non-structural-match-types.stderr
+++ b/tests/ui/pattern/non-structural-match-types.stderr
@@ -1,13 +1,13 @@
 error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns
   --> $DIR/non-structural-match-types.rs:9:9
    |
-LL |         const { || {} } => {},
+LL |         const { || {} } => {}
    |         ^^^^^^^^^^^^^^^
 
 error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns
   --> $DIR/non-structural-match-types.rs:12:9
    |
-LL |         const { async {} } => {},
+LL |         const { async {} } => {}
    |         ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs
index c10c6205a08..2032cf13bc2 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.rs
+++ b/tests/ui/pattern/usefulness/consts-opaque.rs
@@ -30,15 +30,13 @@ fn main() {
     match FOO {
         FOO => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        _ => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
+        _ => {}
     }
 
     match FOO_REF {
         FOO_REF => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        Foo(_) => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
+        Foo(_) => {}
     }
 
     // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
@@ -51,9 +49,8 @@ fn main() {
 
     match BAR {
         Bar => {}
-        BAR => {} // should not be emitting unreachable warning
+        BAR => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        //~| ERROR unreachable pattern
         _ => {}
         //~^ ERROR unreachable pattern
     }
@@ -61,8 +58,7 @@ fn main() {
     match BAR {
         BAR => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        Bar => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
+        Bar => {}
         _ => {}
         //~^ ERROR unreachable pattern
     }
@@ -70,20 +66,16 @@ fn main() {
     match BAR {
         BAR => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        BAR => {} // should not be emitting unreachable warning
+        BAR => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        //~| ERROR unreachable pattern
-        _ => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
+        _ => {}
     }
 
     match BAZ {
         BAZ => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        Baz::Baz1 => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
+        Baz::Baz1 => {}
         _ => {}
-        //~^ ERROR unreachable pattern
     }
 
     match BAZ {
@@ -91,16 +83,13 @@ fn main() {
         BAZ => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => {}
-        //~^ ERROR unreachable pattern
     }
 
     match BAZ {
         BAZ => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        Baz::Baz2 => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
-        _ => {} // should not be emitting unreachable warning
-        //~^ ERROR unreachable pattern
+        Baz::Baz2 => {}
+        _ => {}
     }
 
     type Quux = fn(usize, usize) -> usize;
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index e01b06ccc82..cd88e6a22e4 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -8,7 +8,7 @@ LL |         FOO => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:38:9
+  --> $DIR/consts-opaque.rs:37:9
    |
 LL |         FOO_REF => {}
    |         ^^^^^^^
@@ -17,7 +17,7 @@ LL |         FOO_REF => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:46:9
+  --> $DIR/consts-opaque.rs:44:9
    |
 LL |         FOO_REF_REF => {}
    |         ^^^^^^^^^^^
@@ -29,16 +29,16 @@ LL |         FOO_REF_REF => {}
    = note: `#[warn(indirect_structural_match)]` on by default
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:54:9
+  --> $DIR/consts-opaque.rs:52:9
    |
-LL |         BAR => {} // should not be emitting unreachable warning
+LL |         BAR => {}
    |         ^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:62:9
+  --> $DIR/consts-opaque.rs:59:9
    |
 LL |         BAR => {}
    |         ^^^
@@ -47,7 +47,7 @@ LL |         BAR => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:71:9
+  --> $DIR/consts-opaque.rs:67:9
    |
 LL |         BAR => {}
    |         ^^^
@@ -56,16 +56,16 @@ LL |         BAR => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:73:9
+  --> $DIR/consts-opaque.rs:69:9
    |
-LL |         BAR => {} // should not be emitting unreachable warning
+LL |         BAR => {}
    |         ^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:81:9
+  --> $DIR/consts-opaque.rs:75:9
    |
 LL |         BAZ => {}
    |         ^^^
@@ -74,7 +74,7 @@ LL |         BAZ => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:91:9
+  --> $DIR/consts-opaque.rs:83:9
    |
 LL |         BAZ => {}
    |         ^^^
@@ -83,7 +83,7 @@ LL |         BAZ => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:98:9
+  --> $DIR/consts-opaque.rs:89:9
    |
 LL |         BAZ => {}
    |         ^^^
@@ -92,12 +92,12 @@ LL |         BAZ => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:33:9
+  --> $DIR/consts-opaque.rs:54:9
    |
-LL |         FOO => {}
+LL |         Bar => {}
    |         --- matches any value
-LL |
-LL |         _ => {} // should not be emitting unreachable warning
+...
+LL |         _ => {}
    |         ^ unreachable pattern
    |
 note: the lint level is defined here
@@ -107,120 +107,21 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:40:9
-   |
-LL |         FOO_REF => {}
-   |         ------- matches any value
-LL |
-LL |         Foo(_) => {} // should not be emitting unreachable warning
-   |         ^^^^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:54:9
-   |
-LL |         Bar => {}
-   |         --- matches any value
-LL |         BAR => {} // should not be emitting unreachable warning
-   |         ^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:57:9
+  --> $DIR/consts-opaque.rs:62:9
    |
 LL |         Bar => {}
    |         --- matches any value
-...
-LL |         _ => {}
-   |         ^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:64:9
-   |
-LL |         BAR => {}
-   |         --- matches any value
-LL |
-LL |         Bar => {} // should not be emitting unreachable warning
-   |         ^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:66:9
-   |
-LL |         BAR => {}
-   |         --- matches any value
-...
-LL |         _ => {}
-   |         ^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:73:9
-   |
-LL |         BAR => {}
-   |         --- matches any value
-LL |
-LL |         BAR => {} // should not be emitting unreachable warning
-   |         ^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:76:9
-   |
-LL |         BAR => {}
-   |         --- matches any value
-...
-LL |         _ => {} // should not be emitting unreachable warning
-   |         ^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:83:9
-   |
-LL |         BAZ => {}
-   |         --- matches any value
-LL |
-LL |         Baz::Baz1 => {} // should not be emitting unreachable warning
-   |         ^^^^^^^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:85:9
-   |
-LL |         BAZ => {}
-   |         --- matches any value
-...
-LL |         _ => {}
-   |         ^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:93:9
-   |
-LL |         BAZ => {}
-   |         --- matches any value
-LL |
 LL |         _ => {}
    |         ^ unreachable pattern
 
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:100:9
-   |
-LL |         BAZ => {}
-   |         --- matches any value
-LL |
-LL |         Baz::Baz2 => {} // should not be emitting unreachable warning
-   |         ^^^^^^^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:102:9
-   |
-LL |         BAZ => {}
-   |         --- matches any value
-...
-LL |         _ => {} // should not be emitting unreachable warning
-   |         ^ unreachable pattern
-
 error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered
-  --> $DIR/consts-opaque.rs:135:11
+  --> $DIR/consts-opaque.rs:124:11
    |
 LL |     match WRAPQUUX {
    |           ^^^^^^^^ pattern `Wrap(_)` not covered
    |
 note: `Wrap<fn(usize, usize) -> usize>` defined here
-  --> $DIR/consts-opaque.rs:117:12
+  --> $DIR/consts-opaque.rs:106:12
    |
 LL |     struct Wrap<T>(T);
    |            ^^^^
@@ -231,6 +132,6 @@ LL ~         WRAPQUUX => {},
 LL +         Wrap(_) => todo!()
    |
 
-error: aborting due to 23 previous errors; 1 warning emitted
+error: aborting due to 12 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr
index 6497b7ff535..ac7e5547de9 100644
--- a/tests/ui/privacy/private-in-public-warn.stderr
+++ b/tests/ui/privacy/private-in-public-warn.stderr
@@ -246,7 +246,7 @@ error: trait `traits_where::PrivTr` is more private than the item `traits_where:
   --> $DIR/private-in-public-warn.rs:68:5
    |
 LL |     impl<T> Pub<T> where T: PrivTr {}
-   |     ^^^^^^^^^^^^^^ implementation `traits_where::Pub<T>` is reachable at visibility `pub(crate)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation `traits_where::Pub<T>` is reachable at visibility `pub(crate)`
    |
 note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)`
   --> $DIR/private-in-public-warn.rs:55:5
diff --git a/tests/ui/privacy/private-in-public.stderr b/tests/ui/privacy/private-in-public.stderr
index d8f9fd00716..d3f7f0f637f 100644
--- a/tests/ui/privacy/private-in-public.stderr
+++ b/tests/ui/privacy/private-in-public.stderr
@@ -208,7 +208,7 @@ warning: trait `traits_where::PrivTr` is more private than the item `traits_wher
   --> $DIR/private-in-public.rs:52:5
    |
 LL |     impl<T> Pub<T> where T: PrivTr {
-   |     ^^^^^^^^^^^^^^ implementation `traits_where::Pub<T>` is reachable at visibility `pub(crate)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation `traits_where::Pub<T>` is reachable at visibility `pub(crate)`
    |
 note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)`
   --> $DIR/private-in-public.rs:42:5
diff --git a/tests/ui/privacy/where-priv-type.stderr b/tests/ui/privacy/where-priv-type.stderr
index dcc249c6351..65076645846 100644
--- a/tests/ui/privacy/where-priv-type.stderr
+++ b/tests/ui/privacy/where-priv-type.stderr
@@ -41,8 +41,11 @@ LL | struct PrivTy;
 warning: type `PrivTy` is more private than the item `S`
   --> $DIR/where-priv-type.rs:39:1
    |
-LL | impl S
-   | ^^^^^^ implementation `S` is reachable at visibility `pub`
+LL | / impl S
+LL | |
+LL | | where
+LL | |     PrivTy:
+   | |___________^ implementation `S` is reachable at visibility `pub`
    |
 note: but type `PrivTy` is only usable at visibility `pub(crate)`
   --> $DIR/where-priv-type.rs:8:1
diff --git a/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr b/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr
index c476874332c..ee79ce3f5d7 100644
--- a/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr
+++ b/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr
@@ -41,8 +41,11 @@ LL | trait PrivTr {}
 warning: trait `PrivTr` is more private than the item `S`
   --> $DIR/where-pub-type-impls-priv-trait.rs:41:1
    |
-LL | impl S
-   | ^^^^^^ implementation `S` is reachable at visibility `pub`
+LL | / impl S
+LL | |
+LL | | where
+LL | |     PubTy: PrivTr
+   | |_________________^ implementation `S` is reachable at visibility `pub`
    |
 note: but trait `PrivTr` is only usable at visibility `pub(crate)`
   --> $DIR/where-pub-type-impls-priv-trait.rs:10:1
diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs
index ef56e8e02d0..e0213527c50 100644
--- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs
+++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs
@@ -16,6 +16,36 @@ extern crate std;
 #[macro_use]
 extern crate test_macros;
 
+// Note: the expected output contains this sequence:
+// ```
+// Punct {
+//     ch: '<',
+//     spacing: Joint,
+//     span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0),
+// },
+// Ident {
+//     ident: "B",
+//     span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0),
+// },
+// ```
+// It's surprising to see a `Joint` token tree followed by an `Ident` token
+// tree, because `Joint` is supposed to only be used if the following token is
+// `Punct`.
+//
+// It is because of this code from below:
+// ```
+// struct Foo<#[cfg(FALSE)] A, B>
+// ```
+// When the token stream is formed during parsing, `<` is followed immediately
+// by `#`, which is punctuation, so it is marked `Joint`. But before being
+// passed to the proc macro it is rewritten to this:
+// ```
+// struct Foo<B>
+// ```
+// But the `Joint` marker on the `<` is not updated. Perhaps it should be
+// corrected before being passed to the proc macro? But a prior attempt to do
+// that kind of correction caused the problem seen in #76399, so maybe not.
+
 #[print_helper(a)] //~ WARN derive helper attribute is used before it is introduced
                    //~| WARN this was previously accepted
 #[cfg_attr(not(FALSE), allow(dead_code))]
diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr
index f3f470676e4..1017745de6f 100644
--- a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr
+++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr
@@ -1,5 +1,5 @@
 warning: derive helper attribute is used before it is introduced
-  --> $DIR/issue-75930-derive-cfg.rs:19:3
+  --> $DIR/issue-75930-derive-cfg.rs:49:3
    |
 LL | #[print_helper(a)]
    |   ^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #[derive(Print)]
    = note: `#[warn(legacy_derive_helpers)]` on by default
 
 warning: derive helper attribute is used before it is introduced
-  --> $DIR/issue-75930-derive-cfg.rs:19:3
+  --> $DIR/issue-75930-derive-cfg.rs:49:3
    |
 LL | #[print_helper(a)]
    |   ^^^^^^^^^^^^
diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
index 83afd0d3eae..31a1c44b6df 100644
--- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -26,158 +26,158 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:49:1: 49:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:49:3: 49:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "a",
-                        span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:49:16: 49:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:49:15: 49:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:49:2: 49:19 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "allow",
-                span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:51:24: 51:29 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "dead_code",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:51:30: 51:39 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:51:29: 51:40 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:23:1: 23:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:53:1: 53:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "derive",
-                span: $DIR/issue-75930-derive-cfg.rs:23:3: 23:9 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:53:3: 53:9 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "Print",
-                        span: $DIR/issue-75930-derive-cfg.rs:23:10: 23:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:53:10: 53:15 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:23:9: 23:16 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:16 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:23:2: 23:17 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:53:2: 53:17 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:54:1: 54:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:54:3: 54:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "b",
-                        span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:54:2: 54:19 (#0),
     },
     Ident {
         ident: "struct",
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:1: 55:7 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:8: 55:11 (#0),
     },
     Punct {
         ch: '<',
         spacing: Joint,
-        span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:12 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:12: 25:13 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:12: 55:13 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "cfg",
-                span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:17 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:17 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "FALSE",
-                        span: $DIR/issue-75930-derive-cfg.rs:25:18: 25:23 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:23 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:25:17: 25:24 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:55:17: 55:24 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:13: 25:25 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:25 (#0),
     },
     Ident {
         ident: "A",
-        span: $DIR/issue-75930-derive-cfg.rs:25:26: 25:27 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:26: 55:27 (#0),
     },
     Punct {
         ch: ',',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:27: 25:28 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:27: 55:28 (#0),
     },
     Ident {
         ident: "B",
-        span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:29: 55:30 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:30: 55:31 (#0),
     },
     Group {
         delimiter: Brace,
@@ -185,128 +185,128 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:26:5: 26:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:56:5: 56:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg",
-                        span: $DIR/issue-75930-derive-cfg.rs:26:7: 26:10 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:56:7: 56:10 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "FALSE",
-                                span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:16 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:56:11: 56:16 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:56:10: 56:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:26:6: 26:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:56:6: 56:18 (#0),
             },
             Ident {
                 ident: "first",
-                span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:26:24: 26:25 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:56:24: 56:25 (#0),
             },
             Ident {
                 ident: "String",
-                span: $DIR/issue-75930-derive-cfg.rs:26:26: 26:32 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:56:26: 56:32 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:26:32: 26:33 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:56:32: 56:33 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:27:5: 27:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:5: 57:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg_attr",
-                        span: $DIR/issue-75930-derive-cfg.rs:27:7: 27:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:57:7: 57:15 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "FALSE",
-                                span: $DIR/issue-75930-derive-cfg.rs:27:16: 27:21 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:21 (#0),
                             },
                             Punct {
                                 ch: ',',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:27:21: 27:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:21: 57:22 (#0),
                             },
                             Ident {
                                 ident: "deny",
-                                span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:23: 57:27 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "warnings",
-                                        span: $DIR/issue-75930-derive-cfg.rs:27:28: 27:36 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:57:28: 57:36 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:37 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:27: 57:37 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:38 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:57:15: 57:38 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:27:6: 27:39 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:6: 57:39 (#0),
             },
             Ident {
                 ident: "second",
-                span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:40: 57:46 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:46: 57:47 (#0),
             },
             Ident {
                 ident: "bool",
-                span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:48: 57:52 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:52: 57:53 (#0),
             },
             Ident {
                 ident: "third",
-                span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:58:5: 58:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
@@ -314,145 +314,145 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:29:9: 29:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:59:9: 59:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:11: 29:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:59:11: 59:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:20 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:20 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:21 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:21 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:29:10: 29:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:59:10: 59:22 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:29:23: 29:29 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:29 (#0),
                             },
                             Ident {
                                 ident: "Bar",
-                                span: $DIR/issue-75930-derive-cfg.rs:29:30: 29:33 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:59:30: 59:33 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:29:33: 29:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:59:33: 59:34 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:60:11: 60:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:10: 60:27 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:28: 60:34 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:35: 60:40 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:40: 60:41 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:31:9: 31:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:9: 61:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:31:11: 31:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:61:11: 61:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:20 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:61:15: 61:20 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:31:14: 31:21 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:61:14: 61:21 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:31:10: 31:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:10: 61:22 (#0),
                             },
                             Ident {
                                 ident: "let",
-                                span: $DIR/issue-75930-derive-cfg.rs:31:23: 31:26 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:23: 61:26 (#0),
                             },
                             Ident {
                                 ident: "a",
-                                span: $DIR/issue-75930-derive-cfg.rs:31:27: 31:28 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:27: 61:28 (#0),
                             },
                             Punct {
                                 ch: '=',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:31:29: 31:30 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:29: 61:30 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "25",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:31:31: 31:33 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:31: 61:33 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:31:33: 31:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:33: 61:34 (#0),
                             },
                             Ident {
                                 ident: "match",
-                                span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:9: 62:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:15: 62:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -460,194 +460,194 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:13: 33:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:33:15: 33:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:63:15: 63:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:33:19: 33:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:63:19: 63:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:33:18: 33:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:63:18: 63:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:14: 33:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:14: 63:26 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:27: 33:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:27: 63:31 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:32: 33:33 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:32: 63:33 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:33: 33:34 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:33: 63:34 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:35: 33:37 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:35: 63:37 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:33:37: 33:38 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:37: 63:38 (#0),
                                     },
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg_attr",
-                                                span: $DIR/issue-75930-derive-cfg.rs:34:15: 34:23 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:64:15: 64:23 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:27 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:64:24: 64:27 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:34:28: 34:33 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:64:28: 64:33 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:34:27: 34:34 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:64:27: 64:34 (#0),
                                                     },
                                                     Punct {
                                                         ch: ',',
                                                         spacing: Alone,
-                                                        span: $DIR/issue-75930-derive-cfg.rs:34:34: 34:35 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:64:34: 64:35 (#0),
                                                     },
                                                     Ident {
                                                         ident: "allow",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:64:36: 64:41 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "warnings",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:64:42: 64:50 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:64:41: 64:51 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:52 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:64:23: 64:52 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:14: 34:53 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:14: 64:53 (#0),
                                     },
                                     Ident {
                                         ident: "false",
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:54: 64:59 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:61 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:60: 64:61 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:61: 34:62 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:61: 64:62 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:63: 64:65 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:65: 64:66 (#0),
                                     },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:16 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:16: 35:17 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:18: 65:20 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:20: 66:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:66:10: 66:11 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:38:9: 38:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:38:11: 38:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:68:11: 68:23 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "should_be_removed",
-                                                span: $DIR/issue-75930-derive-cfg.rs:38:24: 38:41 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:68:24: 68:41 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:38:23: 38:42 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:68:23: 68:42 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:38:10: 38:43 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:68:10: 68:43 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:69:9: 69:11 (#0),
                             },
                             Ident {
                                 ident: "removed_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:39:12: 39:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:69:12: 69:22 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:39:22: 39:24 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:69:22: 69:24 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -655,108 +655,108 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:70:13: 70:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:70:14: 70:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:70:16: 70:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:25 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:25 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:26 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:26 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:27 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:70:15: 70:27 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:39:25: 41:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:69:25: 71:10 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:9: 73:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:11: 73:23 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "c",
-                                                span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:73:24: 73:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:23: 73:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:10: 73:27 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:28: 73:29 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:30: 73:33 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:73:34: 73:37 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:73:38: 73:43 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:73:37: 73:44 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:33: 73:45 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:29: 73:46 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:47: 73:49 (#0),
                             },
                             Ident {
                                 ident: "kept_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:50: 73:57 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:57: 73:59 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -764,82 +764,82 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:74:13: 74:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:74:14: 74:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:74:16: 74:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:74:20: 74:23 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:74:24: 74:29 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:74:23: 74:30 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:74:19: 74:31 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:74:15: 74:32 (#0),
                                     },
                                     Ident {
                                         ident: "let",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:13: 75:16 (#0),
                                     },
                                     Ident {
                                         ident: "my_val",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:17: 75:23 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:24: 75:25 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:26: 75:30 (#0),
                                     },
                                     Punct {
                                         ch: ';',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:30: 75:31 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:60: 76:10 (#0),
                             },
                             Ident {
                                 ident: "enum",
-                                span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:78:9: 78:13 (#0),
                             },
                             Ident {
                                 ident: "TupleEnum",
-                                span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:78:14: 78:23 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "Foo",
-                                        span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:79:13: 79:16 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
@@ -847,166 +847,166 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:50:17: 50:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:80:17: 80:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:50:19: 50:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:80:19: 80:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:50:23: 50:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:80:23: 80:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:50:22: 50:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:80:22: 80:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:50:18: 50:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:80:18: 80:30 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:50:31: 50:33 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:80:31: 80:33 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:50:33: 50:34 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:80:33: 80:34 (#0),
                                             },
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:51:17: 51:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:81:17: 81:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:51:19: 51:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:81:19: 81:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:51:23: 51:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:81:23: 81:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:51:22: 51:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:81:22: 81:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:51:18: 51:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:81:18: 81:30 (#0),
                                             },
                                             Ident {
                                                 ident: "bool",
-                                                span: $DIR/issue-75930-derive-cfg.rs:51:31: 51:35 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:81:31: 81:35 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:51:35: 51:36 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:81:35: 81:36 (#0),
                                             },
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:17: 82:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:82:19: 82:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "not",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:26 (#0),
                                                             },
                                                             Group {
                                                                 delimiter: Parenthesis,
                                                                 stream: TokenStream [
                                                                     Ident {
                                                                         ident: "FALSE",
-                                                                        span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0),
+                                                                        span: $DIR/issue-75930-derive-cfg.rs:82:27: 82:32 (#0),
                                                                     },
                                                                 ],
-                                                                span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:82:26: 82:33 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:82:22: 82:34 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:18: 82:35 (#0),
                                             },
                                             Ident {
                                                 ident: "i32",
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:36: 82:39 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:39: 82:40 (#0),
                                             },
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:53:17: 53:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:83:17: 83:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:53:19: 53:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:83:19: 83:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:53:23: 53:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:83:23: 83:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:53:22: 53:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:83:22: 83:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:53:18: 53:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:83:18: 83:30 (#0),
                                             },
                                             Ident {
                                                 ident: "String",
-                                                span: $DIR/issue-75930-derive-cfg.rs:53:31: 53:37 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:83:31: 83:37 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:53:37: 53:38 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:83:37: 83:38 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:83:39: 83:41 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:79:16: 84:14 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:78:24: 85:10 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:87:9: 87:15 (#0),
                             },
                             Ident {
                                 ident: "TupleStruct",
-                                span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:87:16: 87:27 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
@@ -1014,139 +1014,139 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:88:13: 88:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:88:15: 88:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:58:19: 58:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:88:19: 88:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:58:18: 58:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:88:18: 88:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:58:14: 58:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:88:14: 88:26 (#0),
                                     },
                                     Ident {
                                         ident: "String",
-                                        span: $DIR/issue-75930-derive-cfg.rs:58:27: 58:33 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:88:27: 88:33 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:58:33: 58:34 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:88:33: 88:34 (#0),
                                     },
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:13: 89:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:89:15: 89:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:89:23: 89:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:89:22: 89:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:89:18: 89:30 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:14: 89:31 (#0),
                                     },
                                     Ident {
                                         ident: "i32",
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:32: 89:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:35: 89:36 (#0),
                                     },
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:60:13: 60:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:90:13: 90:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:90:15: 90:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:90:19: 90:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:90:18: 90:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:90:14: 90:26 (#0),
                                     },
                                     Ident {
                                         ident: "bool",
-                                        span: $DIR/issue-75930-derive-cfg.rs:60:27: 60:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:90:27: 90:31 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:60:31: 60:32 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:90:31: 90:32 (#0),
                                     },
                                     Ident {
                                         ident: "u8",
-                                        span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:91:13: 91:15 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:87:27: 92:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:92:10: 92:11 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:64:9: 64:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:94:9: 94:11 (#0),
                             },
                             Ident {
                                 ident: "plain_removed_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:64:12: 64:28 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:94:12: 94:28 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:64:28: 64:30 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:94:28: 94:30 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1154,122 +1154,122 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:95:13: 95:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:65:14: 65:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:95:14: 95:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg_attr",
-                                                span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:24 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:95:16: 95:24 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:65:25: 65:28 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:95:25: 95:28 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:65:29: 65:34 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:95:29: 95:34 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:65:28: 65:35 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:95:28: 95:35 (#0),
                                                     },
                                                     Punct {
                                                         ch: ',',
                                                         spacing: Alone,
-                                                        span: $DIR/issue-75930-derive-cfg.rs:65:35: 65:36 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:95:35: 95:36 (#0),
                                                     },
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:65:37: 65:40 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:95:37: 95:40 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:65:41: 65:46 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:95:41: 95:46 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:65:40: 65:47 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:95:40: 95:47 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:65:24: 65:48 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:95:24: 95:48 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:49 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:95:15: 95:49 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:64:31: 66:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:94:31: 96:10 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:98:9: 98:10 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:58:17: 99:6 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:58:12: 99:7 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:99:7: 99:8 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:100:5: 100:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_helper",
-                        span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:100:7: 100:19 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "d",
-                                span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:100:20: 100:21 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:100:19: 100:22 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:100:6: 100:23 (#0),
             },
             Ident {
                 ident: "fourth",
-                span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:101:5: 101:11 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:101:11: 101:12 (#0),
             },
             Ident {
                 ident: "B",
-                span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:101:13: 101:14 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:32: 102:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_helper(b)] struct Foo < B >
@@ -1289,141 +1289,141 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:49:1: 49:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:49:3: 49:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "a",
-                        span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:49:16: 49:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:49:15: 49:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:49:2: 49:19 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "allow",
-                span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:51:24: 51:29 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "dead_code",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:51:30: 51:39 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:51:29: 51:40 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:54:1: 54:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:54:3: 54:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "b",
-                        span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:54:2: 54:19 (#0),
     },
     Ident {
         ident: "struct",
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:1: 55:7 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:8: 55:11 (#0),
     },
     Punct {
         ch: '<',
         spacing: Joint,
-        span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:12 (#0),
     },
     Ident {
         ident: "B",
-        span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:29: 55:30 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:30: 55:31 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "second",
-                span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:40: 57:46 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:46: 57:47 (#0),
             },
             Ident {
                 ident: "bool",
-                span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:48: 57:52 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:57:52: 57:53 (#0),
             },
             Ident {
                 ident: "third",
-                span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:58:5: 58:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
@@ -1431,58 +1431,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:60:11: 60:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:10: 60:27 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:28: 60:34 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:35: 60:40 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:60:40: 60:41 (#0),
                             },
                             Ident {
                                 ident: "match",
-                                span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:9: 62:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:15: 62:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1490,151 +1490,151 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "allow",
-                                                span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:64:36: 64:41 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "warnings",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:64:42: 64:50 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:64:41: 64:51 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0),
                                     },
                                     Ident {
                                         ident: "false",
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:54: 64:59 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:61 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:60: 64:61 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:61: 34:62 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:61: 64:62 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:63: 64:65 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:64:65: 64:66 (#0),
                                     },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:16 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:16: 35:17 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:65:18: 65:20 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:20: 66:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:66:10: 66:11 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:9: 73:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:11: 73:23 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "c",
-                                                span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:73:24: 73:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:23: 73:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:10: 73:27 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:28: 73:29 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:30: 73:33 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:73:34: 73:37 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:73:38: 73:43 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:73:37: 73:44 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:73:33: 73:45 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:29: 73:46 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:47: 73:49 (#0),
                             },
                             Ident {
                                 ident: "kept_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:50: 73:57 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:57: 73:59 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1642,82 +1642,82 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:74:13: 74:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:74:14: 74:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:74:16: 74:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:74:20: 74:23 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:74:24: 74:29 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:74:23: 74:30 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:74:19: 74:31 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:74:15: 74:32 (#0),
                                     },
                                     Ident {
                                         ident: "let",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:13: 75:16 (#0),
                                     },
                                     Ident {
                                         ident: "my_val",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:17: 75:23 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:24: 75:25 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:26: 75:30 (#0),
                                     },
                                     Punct {
                                         ch: ';',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:75:30: 75:31 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:73:60: 76:10 (#0),
                             },
                             Ident {
                                 ident: "enum",
-                                span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:78:9: 78:13 (#0),
                             },
                             Ident {
                                 ident: "TupleEnum",
-                                span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:78:14: 78:23 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "Foo",
-                                        span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:79:13: 79:16 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
@@ -1725,64 +1725,64 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:17: 82:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:82:19: 82:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "not",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:26 (#0),
                                                             },
                                                             Group {
                                                                 delimiter: Parenthesis,
                                                                 stream: TokenStream [
                                                                     Ident {
                                                                         ident: "FALSE",
-                                                                        span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0),
+                                                                        span: $DIR/issue-75930-derive-cfg.rs:82:27: 82:32 (#0),
                                                                     },
                                                                 ],
-                                                                span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:82:26: 82:33 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:82:22: 82:34 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:18: 82:35 (#0),
                                             },
                                             Ident {
                                                 ident: "i32",
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:36: 82:39 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:82:39: 82:40 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:83:39: 83:41 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:79:16: 84:14 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:78:24: 85:10 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:87:9: 87:15 (#0),
                             },
                             Ident {
                                 ident: "TupleStruct",
-                                span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:87:16: 87:27 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
@@ -1790,115 +1790,115 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:13: 89:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:89:15: 89:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:89:23: 89:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:89:22: 89:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:89:18: 89:30 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:14: 89:31 (#0),
                                     },
                                     Ident {
                                         ident: "i32",
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:32: 89:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:89:35: 89:36 (#0),
                                     },
                                     Ident {
                                         ident: "u8",
-                                        span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:91:13: 91:15 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:87:27: 92:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:92:10: 92:11 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:98:9: 98:10 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:58:17: 99:6 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:58:12: 99:7 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:99:7: 99:8 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:100:5: 100:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_helper",
-                        span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:100:7: 100:19 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "d",
-                                span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:100:20: 100:21 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:100:19: 100:22 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:100:6: 100:23 (#0),
             },
             Ident {
                 ident: "fourth",
-                span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:101:5: 101:11 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:101:11: 101:12 (#0),
             },
             Ident {
                 ident: "B",
-                span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:101:13: 101:14 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:55:32: 102:2 (#0),
     },
 ]
diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr
index 4f3f9d1eb3a..21f1fdba886 100644
--- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr
+++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr
@@ -2,13 +2,13 @@ error: literal out of range for `u8`
   --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:5:14
    |
 LL |         251..257 => {}
-   |              ^^^ this value doesn't fit in `u8` whose maximum value is `255`
+   |              ^^^ this value does not fit into the type `u8` whose range is `0..=255`
 
 error: literal out of range for `u8`
   --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:7:15
    |
 LL |         251..=256 => {}
-   |               ^^^ this value doesn't fit in `u8` whose maximum value is `255`
+   |               ^^^ this value does not fit into the type `u8` whose range is `0..=255`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/regions/closure-in-projection-issue-97405.stderr b/tests/ui/regions/closure-in-projection-issue-97405.stderr
index c08f1059ebf..7070dfef138 100644
--- a/tests/ui/regions/closure-in-projection-issue-97405.stderr
+++ b/tests/ui/regions/closure-in-projection-issue-97405.stderr
@@ -3,27 +3,33 @@ error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not li
    |
 LL |     assert_static(opaque(async move { t; }).next());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the associated type `<impl Iterator as Iterator>::Item` must be valid for the static lifetime...
+   |     ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
-   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
 error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:26:5
    |
 LL |     assert_static(opaque(move || { t; }).next());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the associated type `<impl Iterator as Iterator>::Item` must be valid for the static lifetime...
+   |     ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
-   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
 error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:28:5
    |
 LL |     assert_static(opaque(opaque(async move { t; }).next()).next());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the associated type `<impl Iterator as Iterator>::Item` must be valid for the static lifetime...
+   |     ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
    |
    = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
-   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/regions/regions-close-associated-type-into-object.stderr b/tests/ui/regions/regions-close-associated-type-into-object.stderr
index f7dcaa9d97e..6fb514377a6 100644
--- a/tests/ui/regions/regions-close-associated-type-into-object.stderr
+++ b/tests/ui/regions/regions-close-associated-type-into-object.stderr
@@ -3,36 +3,56 @@ error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
    |
 LL |     Box::new(item)
    |     ^^^^^^^^^^^^^^
+   |     |
+   |     the associated type `<T as Iter>::Item` must be valid for the static lifetime...
+   |     ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
-   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound
+   |
+LL | fn bad1<T: Iter>(v: T) -> Box<dyn X + 'static> where <T as Iter>::Item: 'static
+   |                                                ++++++++++++++++++++++++++++++++
 
 error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
   --> $DIR/regions-close-associated-type-into-object.rs:22:5
    |
 LL |     Box::new(item)
    |     ^^^^^^^^^^^^^^
+   |     |
+   |     the associated type `<T as Iter>::Item` must be valid for the static lifetime...
+   |     ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
-   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+LL |     where Box<T::Item> : X, <T as Iter>::Item: 'static
+   |                           ++++++++++++++++++++++++++++
 
 error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
   --> $DIR/regions-close-associated-type-into-object.rs:28:5
    |
+LL | fn bad3<'a, T: Iter>(v: T) -> Box<dyn X + 'a>
+   |         -- the associated type `<T as Iter>::Item` must be valid for the lifetime `'a` as defined here...
+...
 LL |     Box::new(item)
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
-   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound
+   |
+LL | fn bad3<'a, T: Iter>(v: T) -> Box<dyn X + 'a> where <T as Iter>::Item: 'a
+   |                                               +++++++++++++++++++++++++++
 
 error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
   --> $DIR/regions-close-associated-type-into-object.rs:35:5
    |
+LL | fn bad4<'a, T: Iter>(v: T) -> Box<dyn X + 'a>
+   |         -- the associated type `<T as Iter>::Item` must be valid for the lifetime `'a` as defined here...
+...
 LL |     Box::new(item)
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
-   = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds
+LL |     where Box<T::Item> : X, <T as Iter>::Item: 'a
+   |                           +++++++++++++++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/regions/regions-close-object-into-object-4.stderr b/tests/ui/regions/regions-close-object-into-object-4.stderr
index 3ff7f891c66..b8b414b7e12 100644
--- a/tests/ui/regions/regions-close-object-into-object-4.stderr
+++ b/tests/ui/regions/regions-close-object-into-object-4.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |     ^^^^^^^^
+   |     |
+   |     the parameter type `U` must be valid for the static lifetime...
+   |     ...so that the type `U` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |              +++++++++
@@ -13,9 +16,12 @@ error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `U` must be valid for the static lifetime...
+   |     ...so that the type `U` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |              +++++++++
@@ -24,10 +30,13 @@ error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `U` must be valid for the static lifetime...
+   |     ...so that the type `U` will meet its required lifetime bounds
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |              +++++++++
@@ -62,9 +71,12 @@ error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:9:14
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |              ^^^^^^
+   |              |
+   |              the parameter type `U` must be valid for the static lifetime...
+   |              ...so that the type `U` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |              +++++++++
diff --git a/tests/ui/regions/regions-close-object-into-object-5.stderr b/tests/ui/regions/regions-close-object-into-object-5.stderr
index 88c13483263..4a2f4f847a3 100644
--- a/tests/ui/regions/regions-close-object-into-object-5.stderr
+++ b/tests/ui/regions/regions-close-object-into-object-5.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |           +++++++++
@@ -13,9 +16,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |           +++++++++
@@ -24,10 +30,13 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |           +++++++++
@@ -45,9 +54,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:14
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |              ^^^^^^
+   |              |
+   |              the parameter type `T` must be valid for the static lifetime...
+   |              ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |           +++++++++
diff --git a/tests/ui/regions/regions-close-over-type-parameter-1.stderr b/tests/ui/regions/regions-close-over-type-parameter-1.stderr
index b7b557d7a60..1cd5b7f2250 100644
--- a/tests/ui/regions/regions-close-over-type-parameter-1.stderr
+++ b/tests/ui/regions/regions-close-over-type-parameter-1.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:11:5
    |
 LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^
+   |     |
+   |     the parameter type `A` must be valid for the static lifetime...
+   |     ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'static> {
    |                              +++++++++
@@ -12,10 +15,12 @@ LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'stati
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:20:5
    |
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
+   |                     -- the parameter type `A` must be valid for the lifetime `'b` as defined here...
 LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box<dyn SomeTrait + 'b> {
    |                                           ++++
diff --git a/tests/ui/regions/regions-close-param-into-object.stderr b/tests/ui/regions/regions-close-param-into-object.stderr
index 9162be5b93c..385441d3282 100644
--- a/tests/ui/regions/regions-close-param-into-object.stderr
+++ b/tests/ui/regions/regions-close-param-into-object.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:6:5
    |
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     where T : X + 'static
    |                 +++++++++
@@ -13,9 +16,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:12:5
    |
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static>
    |        +++++++++
@@ -23,10 +29,13 @@ LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static>
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:18:5
    |
+LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
+   |       -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     where T : X + 'a
    |                 ++++
@@ -34,10 +43,13 @@ LL |     where T : X + 'a
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:24:5
    |
+LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
+   |       -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn p4<'a,T: 'a>(v: Box<T>) -> Box<dyn X + 'a>
    |           ++++
diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-1.stderr b/tests/ui/regions/regions-implied-bounds-projection-gap-1.stderr
index 7c9f405563c..8c1791fc11d 100644
--- a/tests/ui/regions/regions-implied-bounds-projection-gap-1.stderr
+++ b/tests/ui/regions/regions-implied-bounds-projection-gap-1.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:5
    |
+LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
+   |         -- the parameter type `T` must be valid for the lifetime `'x` as defined here...
+LL | {
 LL |     wf::<&'x T>();
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo)
    |                          ++++
diff --git a/tests/ui/regions/regions-infer-bound-from-trait-self.stderr b/tests/ui/regions/regions-infer-bound-from-trait-self.stderr
index e88f79a3a8c..d0c4b9a57e0 100644
--- a/tests/ui/regions/regions-infer-bound-from-trait-self.stderr
+++ b/tests/ui/regions/regions-infer-bound-from-trait-self.stderr
@@ -1,11 +1,16 @@
 error[E0309]: the parameter type `Self` may not live long enough
   --> $DIR/regions-infer-bound-from-trait-self.rs:46:9
    |
+LL | trait InheritsFromNothing<'a> : Sized {
+   |                           -- the parameter type `Self` must be valid for the lifetime `'a` as defined here...
+LL |     fn foo(self, x: Inv<'a>) {
 LL |         check_bound(x, self)
-   |         ^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^ ...so that the type `Self` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the type `Self` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound
+   |
+LL | trait InheritsFromNothing<'a> : Sized where Self: 'a {
+   |                                       ++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/regions/regions-infer-bound-from-trait.stderr b/tests/ui/regions/regions-infer-bound-from-trait.stderr
index 3ee71543d15..b9be11a4639 100644
--- a/tests/ui/regions/regions-infer-bound-from-trait.stderr
+++ b/tests/ui/regions/regions-infer-bound-from-trait.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:33:5
    |
+LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
+   |         -- the parameter type `A` must be valid for the lifetime `'a` as defined here...
 LL |     check_bound(x, a)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) {
    |             ++++
@@ -12,10 +14,12 @@ LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) {
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:37:5
    |
+LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
+   |         -- the parameter type `A` must be valid for the lifetime `'a` as defined here...
 LL |     check_bound(x, a)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) {
    |                        ++++
diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr
index 0c388f5fe41..041f7ebc0aa 100644
--- a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr
+++ b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr
@@ -2,14 +2,17 @@ error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/dont-infer-static.rs:6:10
    |
 LL |     bar: Bar<U>
-   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
+   |          ^^^^^^
+   |          |
+   |          the parameter type `U` must be valid for the static lifetime...
+   |          ...so that the type `U` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
   --> $DIR/dont-infer-static.rs:8:15
    |
 LL | struct Bar<T: 'static> {
    |               ^^^^^^^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | struct Foo<U: 'static> {
    |             +++++++++
diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
index 2c660b28500..5b605f3eef5 100644
--- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
+++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:17:18
    |
+LL | enum Ref1<'a, T> {
+   |           -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     Ref1Variant1(RequireOutlives<'a, T>),
    |                  ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | enum Ref1<'a, T: 'a> {
    |                ++++
@@ -12,10 +14,13 @@ LL | enum Ref1<'a, T: 'a> {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:22:25
    |
+LL | enum Ref2<'a, T> {
+   |           -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+LL |     Ref2Variant1,
 LL |     Ref2Variant2(isize, RequireOutlives<'a, T>),
    |                         ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | enum Ref2<'a, T: 'a> {
    |                ++++
@@ -23,10 +28,12 @@ LL | enum Ref2<'a, T: 'a> {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:35:23
    |
+LL | enum RefDouble<'a, 'b, T> {
+   |                    -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
 LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>),
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | enum RefDouble<'a, 'b, T: 'b> {
    |                         ++++
diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
index 34ff1362cf3..eb17ce736f7 100644
--- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
+++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-struct-not-wf.rs:13:16
    |
+LL | impl<'a, T> Trait<'a, T> for usize {
+   |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     type Out = &'a T;
    |                ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<'a, T: 'a> Trait<'a, T> for usize {
    |           ++++
@@ -12,6 +14,8 @@ LL | impl<'a, T: 'a> Trait<'a, T> for usize {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-struct-not-wf.rs:21:16
    |
+LL | impl<'a, T> Trait<'a, T> for u32 {
+   |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     type Out = RefOk<'a, T>;
    |                ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -20,7 +24,7 @@ note: ...that is required by this bound
    |
 LL | struct RefOk<'a, T:'a> {
    |                    ^^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<'a, T: 'a> Trait<'a, T> for u32 {
    |           ++++
diff --git a/tests/ui/specialization/issue-52050.stderr b/tests/ui/specialization/issue-52050.stderr
index c263fe46724..85aac16f6d0 100644
--- a/tests/ui/specialization/issue-52050.stderr
+++ b/tests/ui/specialization/issue-52050.stderr
@@ -11,11 +11,13 @@ LL | #![feature(specialization)]
 error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`
   --> $DIR/issue-52050.rs:28:1
    |
-LL | impl<I> IntoPyDictPointer for I
-   | ------------------------------- first implementation here
+LL | / impl<I> IntoPyDictPointer for I
+LL | | where
+LL | |     I: Iterator,
+   | |________________- first implementation here
 ...
-LL | impl IntoPyDictPointer for ()
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+LL |   impl IntoPyDictPointer for ()
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
    |
    = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
 
diff --git a/tests/ui/suggestions/issue-102972.fixed b/tests/ui/suggestions/issue-102972.fixed
new file mode 100644
index 00000000000..ebd73b2dc14
--- /dev/null
+++ b/tests/ui/suggestions/issue-102972.fixed
@@ -0,0 +1,41 @@
+// run-rustfix
+
+fn test1() {
+    let mut chars = "Hello".chars();
+    let iter = chars.by_ref();
+    while let Some(_c) = iter.next() {
+        iter.next(); //~ ERROR cannot borrow `chars` as mutable more than once at a time
+    }
+}
+
+fn test2() {
+    let v = vec![1, 2, 3];
+    let mut iter = v.iter();
+    while let Some(_i) = iter.next() {
+        iter.next(); //~ ERROR borrow of moved value: `iter`
+    }
+}
+
+fn test3() {
+    let v = vec![(), (), ()];
+    let mut i = v.iter();
+    let iter = i.by_ref();
+    while let Some(()) = iter.next() {
+        iter.next(); //~ ERROR cannot borrow `i`
+    }
+}
+
+fn test4() {
+    let v = vec![(), (), ()];
+    let mut iter = v.iter();
+    while let Some(()) = iter.next() {
+        iter.next(); //~ ERROR borrow of moved value: `iter`
+    }
+}
+
+fn main() {
+    test1();
+    test2();
+    test3();
+    test4();
+}
diff --git a/tests/ui/suggestions/issue-102972.rs b/tests/ui/suggestions/issue-102972.rs
index 106288b054d..1f8e9776759 100644
--- a/tests/ui/suggestions/issue-102972.rs
+++ b/tests/ui/suggestions/issue-102972.rs
@@ -1,3 +1,5 @@
+// run-rustfix
+
 fn test1() {
     let mut chars = "Hello".chars();
     for _c in chars.by_ref() {
@@ -13,4 +15,25 @@ fn test2() {
     }
 }
 
-fn main() { }
+fn test3() {
+    let v = vec![(), (), ()];
+    let mut i = v.iter();
+    for () in i.by_ref() {
+        i.next(); //~ ERROR cannot borrow `i`
+    }
+}
+
+fn test4() {
+    let v = vec![(), (), ()];
+    let mut iter = v.iter();
+    for () in iter {
+        iter.next(); //~ ERROR borrow of moved value: `iter`
+    }
+}
+
+fn main() {
+    test1();
+    test2();
+    test3();
+    test4();
+}
diff --git a/tests/ui/suggestions/issue-102972.stderr b/tests/ui/suggestions/issue-102972.stderr
index 3303d6bbc3f..4b0d3b96f85 100644
--- a/tests/ui/suggestions/issue-102972.stderr
+++ b/tests/ui/suggestions/issue-102972.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `chars` as mutable more than once at a time
-  --> $DIR/issue-102972.rs:4:9
+  --> $DIR/issue-102972.rs:6:9
    |
 LL |     for _c in chars.by_ref() {
    |               --------------
@@ -8,9 +8,17 @@ LL |     for _c in chars.by_ref() {
    |               first borrow later used here
 LL |         chars.next();
    |         ^^^^^ second mutable borrow occurs here
+   |
+   = note: a for loop advances the iterator for you, the result is stored in `_c`
+help: if you want to call `next` on a iterator within the loop, consider using `while let`
+   |
+LL ~     let iter = chars.by_ref();
+LL ~     while let Some(_c) = iter.next() {
+LL ~         iter.next();
+   |
 
 error[E0382]: borrow of moved value: `iter`
-  --> $DIR/issue-102972.rs:12:9
+  --> $DIR/issue-102972.rs:14:9
    |
 LL |     let mut iter = v.iter();
    |         -------- move occurs because `iter` has type `std::slice::Iter<'_, i32>`, which does not implement the `Copy` trait
@@ -19,10 +27,52 @@ LL |     for _i in iter {
 LL |         iter.next();
    |         ^^^^ value borrowed here after move
    |
+   = note: a for loop advances the iterator for you, the result is stored in `_i`
 note: `into_iter` takes ownership of the receiver `self`, which moves `iter`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: if you want to call `next` on a iterator within the loop, consider using `while let`
+   |
+LL |     while let Some(_i) = iter.next() {
+   |     ~~~~~~~~~~~~~~~  ~~~     +++++++
+
+error[E0499]: cannot borrow `i` as mutable more than once at a time
+  --> $DIR/issue-102972.rs:22:9
+   |
+LL |     for () in i.by_ref() {
+   |               ----------
+   |               |
+   |               first mutable borrow occurs here
+   |               first borrow later used here
+LL |         i.next();
+   |         ^ second mutable borrow occurs here
+   |
+   = note: a for loop advances the iterator for you, the result is stored in its pattern
+help: if you want to call `next` on a iterator within the loop, consider using `while let`
+   |
+LL ~     let iter = i.by_ref();
+LL ~     while let Some(()) = iter.next() {
+LL ~         iter.next();
+   |
+
+error[E0382]: borrow of moved value: `iter`
+  --> $DIR/issue-102972.rs:30:9
+   |
+LL |     let mut iter = v.iter();
+   |         -------- move occurs because `iter` has type `std::slice::Iter<'_, ()>`, which does not implement the `Copy` trait
+LL |     for () in iter {
+   |               ---- `iter` moved due to this implicit call to `.into_iter()`
+LL |         iter.next();
+   |         ^^^^ value borrowed here after move
+   |
+   = note: a for loop advances the iterator for you, the result is stored in its pattern
+note: `into_iter` takes ownership of the receiver `self`, which moves `iter`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: if you want to call `next` on a iterator within the loop, consider using `while let`
+   |
+LL |     while let Some(()) = iter.next() {
+   |     ~~~~~~~~~~~~~~~  ~~~     +++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0382, E0499.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/suggestions/lifetimes/issue-105544.fixed b/tests/ui/suggestions/lifetimes/issue-105544.fixed
index 47087eb4749..c92114e1812 100644
--- a/tests/ui/suggestions/lifetimes/issue-105544.fixed
+++ b/tests/ui/suggestions/lifetimes/issue-105544.fixed
@@ -2,7 +2,7 @@
 
 #![allow(warnings)]
 
-fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized` must be valid for the anonymous lifetime defined here...
+fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + 'a { //~ NOTE the parameter type `impl Sized` must be valid for the anonymous lifetime defined here...
 //~^ HELP consider adding an explicit lifetime bound
     (d, p)
     //~^ ERROR the parameter type `impl Sized` may not live long enough
@@ -10,19 +10,20 @@ fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the
 }
 
 fn foo1<'b>(d: impl Sized + 'b, p: &'b mut ()) -> impl Sized + '_ {
-//~^ HELP consider adding an explicit lifetime bound...
+//~^ NOTE the parameter type `impl Sized` must be valid for the lifetime `'b` as defined here...
+//~| HELP consider adding an explicit lifetime bound
     (d, p) //~ NOTE ...so that the type `impl Sized` will meet its required lifetime bounds
     //~^ ERROR the parameter type `impl Sized` may not live long enough
 }
 
-fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here...
+fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + 'b { //~ NOTE the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here...
 //~^ HELP consider adding an explicit lifetime bound
     (d, p)
     //~^ ERROR the parameter type `impl Sized + 'a` may not live long enough
     //~| NOTE ...so that the type `impl Sized + 'a` will meet its required lifetime bounds
 }
 
-fn bar<'a, T : Sized + 'a>(d: T, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
+fn bar<'a, T : Sized + 'a>(d: T, p: &'a  mut ()) -> impl Sized + 'a { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
 //~^ HELP consider adding an explicit lifetime bound
     (d, p)
     //~^ ERROR the parameter type `T` may not live long enough
@@ -30,12 +31,13 @@ fn bar<'a, T : Sized + 'a>(d: T, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE th
 }
 
 fn bar1<'b, T : Sized + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ {
-//~^ HELP consider adding an explicit lifetime bound...
+//~^ NOTE the parameter type `T` must be valid for the lifetime `'b` as defined here...
+//~| HELP consider adding an explicit lifetime bound
     (d, p) //~ NOTE ...so that the type `T` will meet its required lifetime bounds
     //~^ ERROR the parameter type `T` may not live long enough
 }
 
-fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
+fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + 'b { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
 //~^ HELP consider adding an explicit lifetime bound
     (d, p)
     //~^ ERROR the parameter type `T` may not live long enough
diff --git a/tests/ui/suggestions/lifetimes/issue-105544.rs b/tests/ui/suggestions/lifetimes/issue-105544.rs
index bd3bc1ef9bd..bbd0f097f84 100644
--- a/tests/ui/suggestions/lifetimes/issue-105544.rs
+++ b/tests/ui/suggestions/lifetimes/issue-105544.rs
@@ -10,7 +10,8 @@ fn foo(d: impl Sized, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter ty
 }
 
 fn foo1<'b>(d: impl Sized, p: &'b mut ()) -> impl Sized + '_ {
-//~^ HELP consider adding an explicit lifetime bound...
+//~^ NOTE the parameter type `impl Sized` must be valid for the lifetime `'b` as defined here...
+//~| HELP consider adding an explicit lifetime bound
     (d, p) //~ NOTE ...so that the type `impl Sized` will meet its required lifetime bounds
     //~^ ERROR the parameter type `impl Sized` may not live long enough
 }
@@ -30,7 +31,8 @@ fn bar<T : Sized>(d: T, p: & mut ()) -> impl Sized + '_ { //~ NOTE the parameter
 }
 
 fn bar1<'b, T : Sized>(d: T, p: &'b mut ()) -> impl Sized + '_ {
-//~^ HELP consider adding an explicit lifetime bound...
+//~^ NOTE the parameter type `T` must be valid for the lifetime `'b` as defined here...
+//~| HELP consider adding an explicit lifetime bound
     (d, p) //~ NOTE ...so that the type `T` will meet its required lifetime bounds
     //~^ ERROR the parameter type `T` may not live long enough
 }
diff --git a/tests/ui/suggestions/lifetimes/issue-105544.stderr b/tests/ui/suggestions/lifetimes/issue-105544.stderr
index 08fe21b11b5..553643c0c3f 100644
--- a/tests/ui/suggestions/lifetimes/issue-105544.stderr
+++ b/tests/ui/suggestions/lifetimes/issue-105544.stderr
@@ -1,108 +1,86 @@
 error[E0311]: the parameter type `impl Sized` may not live long enough
   --> $DIR/issue-105544.rs:7:5
    |
-LL |     (d, p)
-   |     ^^^^^^
-   |
-note: the parameter type `impl Sized` must be valid for the anonymous lifetime defined here...
-  --> $DIR/issue-105544.rs:5:26
-   |
 LL | fn foo(d: impl Sized, p: &mut ()) -> impl Sized + '_ {
-   |                          ^^^^^^^
-note: ...so that the type `impl Sized` will meet its required lifetime bounds
-  --> $DIR/issue-105544.rs:7:5
-   |
+   |                          ------- the parameter type `impl Sized` must be valid for the anonymous lifetime defined here...
+LL |
 LL |     (d, p)
-   |     ^^^^^^
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^ ...so that the type `impl Sized` will meet its required lifetime bounds
    |
-LL | fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + '_ {
-   |       ++++               ++++      ++
+help: consider adding an explicit lifetime bound
+   |
+LL | fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + 'a {
+   |       ++++               ++++      ++                         ~~
 
 error[E0309]: the parameter type `impl Sized` may not live long enough
-  --> $DIR/issue-105544.rs:14:5
+  --> $DIR/issue-105544.rs:15:5
    |
+LL | fn foo1<'b>(d: impl Sized, p: &'b mut ()) -> impl Sized + '_ {
+   |         -- the parameter type `impl Sized` must be valid for the lifetime `'b` as defined here...
+...
 LL |     (d, p)
    |     ^^^^^^ ...so that the type `impl Sized` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn foo1<'b>(d: impl Sized + 'b, p: &'b mut ()) -> impl Sized + '_ {
    |                           ++++
 
 error[E0311]: the parameter type `impl Sized + 'a` may not live long enough
-  --> $DIR/issue-105544.rs:20:5
-   |
-LL |     (d, p)
-   |     ^^^^^^
-   |
-note: the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here...
-  --> $DIR/issue-105544.rs:18:36
+  --> $DIR/issue-105544.rs:21:5
    |
 LL | fn foo2<'a>(d: impl Sized + 'a, p: &mut ()) -> impl Sized + '_ {
-   |                                    ^^^^^^^
-note: ...so that the type `impl Sized + 'a` will meet its required lifetime bounds
-  --> $DIR/issue-105544.rs:20:5
-   |
+   |                                    ------- the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here...
+LL |
 LL |     (d, p)
-   |     ^^^^^^
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^ ...so that the type `impl Sized + 'a` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-LL | fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + '_ {
-   |         +++                        ++++      ++
+LL | fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + 'b {
+   |         +++                        ++++      ++                         ~~
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/issue-105544.rs:27:5
-   |
-LL |     (d, p)
-   |     ^^^^^^
-   |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/issue-105544.rs:25:28
+  --> $DIR/issue-105544.rs:28:5
    |
 LL | fn bar<T : Sized>(d: T, p: & mut ()) -> impl Sized + '_ {
-   |                            ^^^^^^^^
-note: ...so that the type `T` will meet its required lifetime bounds
-  --> $DIR/issue-105544.rs:27:5
-   |
+   |                            -------- the parameter type `T` must be valid for the anonymous lifetime defined here...
+LL |
 LL |     (d, p)
-   |     ^^^^^^
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-LL | fn bar<'a, T : Sized + 'a>(d: T, p: &'a mut ()) -> impl Sized + '_ {
-   |        +++           ++++            ++
+LL | fn bar<'a, T : Sized + 'a>(d: T, p: &'a  mut ()) -> impl Sized + 'a {
+   |        +++           ++++            ++                          ~~
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/issue-105544.rs:34:5
+  --> $DIR/issue-105544.rs:36:5
    |
+LL | fn bar1<'b, T : Sized>(d: T, p: &'b mut ()) -> impl Sized + '_ {
+   |         -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
+...
 LL |     (d, p)
    |     ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn bar1<'b, T : Sized + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ {
    |                       ++++
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/issue-105544.rs:40:5
-   |
-LL |     (d, p)
-   |     ^^^^^^
-   |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/issue-105544.rs:38:38
+  --> $DIR/issue-105544.rs:42:5
    |
 LL | fn bar2<'a, T : Sized + 'a>(d: T, p: &mut ()) -> impl Sized + '_ {
-   |                                      ^^^^^^^
-note: ...so that the type `T` will meet its required lifetime bounds
-  --> $DIR/issue-105544.rs:40:5
-   |
+   |                                      ------- the parameter type `T` must be valid for the anonymous lifetime defined here...
+LL |
 LL |     (d, p)
-   |     ^^^^^^
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
    |
-LL | fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ {
-   |         +++                    ++++            ++
+LL | fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + 'b {
+   |         +++                    ++++            ++                         ~~
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed
index 4013d98c3cf..474986283fc 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed
@@ -19,11 +19,16 @@ trait Test {
     fn test(&self);
 }
 
-fn func<'a, T: Test + 'a>(foo: &'a Foo<'a>, t: T) {
+fn func<'a, T: Test + 'a>(_dummy: &Foo, foo: &Foo<'a>, t: T) {
     foo.bar(move |_| {
     //~^ ERROR the parameter type `T` may not live long enough
         t.test();
     });
 }
 
+// Test that the suggested fix does not overconstrain `func`. See #115375.
+fn test_func<'a, T: Test + 'a>(dummy: &Foo, foo: &Foo<'a>, t: T) {
+    func(dummy, foo, t);
+}
+
 fn main() {}
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs
index 4096d95e5fd..99c8e9626af 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs
@@ -19,11 +19,16 @@ trait Test {
     fn test(&self);
 }
 
-fn func<T: Test>(foo: &Foo, t: T) {
+fn func<T: Test>(_dummy: &Foo, foo: &Foo, t: T) {
     foo.bar(move |_| {
     //~^ ERROR the parameter type `T` may not live long enough
         t.test();
     });
 }
 
+// Test that the suggested fix does not overconstrain `func`. See #115375.
+fn test_func<'a, T: Test + 'a>(dummy: &Foo, foo: &Foo<'a>, t: T) {
+    func(dummy, foo, t);
+}
+
 fn main() {}
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
index 936d87f7968..6c63e1ada61 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
@@ -1,29 +1,18 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/missing-lifetimes-in-signature-2.rs:23:5
    |
+LL |   fn func<T: Test>(_dummy: &Foo, foo: &Foo, t: T) {
+   |                                        --- the parameter type `T` must be valid for the anonymous lifetime defined here...
 LL | /     foo.bar(move |_| {
 LL | |
 LL | |         t.test();
 LL | |     });
-   | |______^
+   | |______^ ...so that the type `T` will meet its required lifetime bounds
    |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature-2.rs:22:24
+help: consider adding an explicit lifetime bound
    |
-LL | fn func<T: Test>(foo: &Foo, t: T) {
-   |                        ^^^
-note: ...so that the type `T` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature-2.rs:23:5
-   |
-LL | /     foo.bar(move |_| {
-LL | |
-LL | |         t.test();
-LL | |     });
-   | |______^
-help: consider adding an explicit lifetime bound...
-   |
-LL | fn func<'a, T: Test + 'a>(foo: &'a Foo<'a>, t: T) {
-   |         +++         ++++        ++    ++++
+LL | fn func<'a, T: Test + 'a>(_dummy: &Foo, foo: &Foo<'a>, t: T) {
+   |         +++         ++++                         ++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 318ea4083d1..64af17c830e 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -28,28 +28,18 @@ LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:30:5
    |
+LL |   fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                            ------ the parameter type `G` must be valid for the anonymous lifetime defined here...
+...
 LL | /     move || {
 LL | |
 LL | |         *dest = g.get();
 LL | |     }
-   | |_____^
-   |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:26:26
-   |
-LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |                          ^^^^^^
-note: ...so that the type `G` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:30:5
+   | |_____^ ...so that the type `G` will meet its required lifetime bounds
    |
-LL | /     move || {
-LL | |
-LL | |         *dest = g.get();
-LL | |     }
-   | |_____^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
-LL ~ fn bar<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_
+LL ~ fn bar<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
 LL | where
 LL ~     G: Get<T> + 'a,
    |
@@ -57,85 +47,53 @@ LL ~     G: Get<T> + 'a,
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:52:5
    |
+LL |   fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                    ------ the parameter type `G` must be valid for the anonymous lifetime defined here...
+...
 LL | /     move || {
 LL | |
 LL | |         *dest = g.get();
 LL | |     }
-   | |_____^
-   |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:48:34
-   |
-LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |                                  ^^^^^^
-note: ...so that the type `G` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:52:5
+   | |_____^ ...so that the type `G` will meet its required lifetime bounds
    |
-LL | /     move || {
-LL | |
-LL | |         *dest = g.get();
-LL | |     }
-   | |_____^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
-LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + '_
-   |        +++           ++++                  ++
+LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + 'b
+   |        +++           ++++                  ++                           ~~
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:61:9
    |
+LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                                 ------ the parameter type `G` must be valid for the anonymous lifetime defined here...
 LL | /         move || {
 LL | |
 LL | |             *dest = g.get();
 LL | |         }
-   | |_________^
+   | |_________^ ...so that the type `G` will meet its required lifetime bounds
    |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:60:47
+help: consider adding an explicit lifetime bound
    |
-LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-   |                                               ^^^^^^
-note: ...so that the type `G` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:61:9
-   |
-LL | /         move || {
-LL | |
-LL | |             *dest = g.get();
-LL | |         }
-   | |_________^
-help: consider adding an explicit lifetime bound...
-   |
-LL |     fn qux<'c, 'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &'c mut T) -> impl FnOnce() + '_ {
-   |            +++                    ++++                  ++
+LL |     fn qux<'c, 'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &'c mut T) -> impl FnOnce() + 'c {
+   |            +++                    ++++                  ++                           ~~
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:73:5
    |
+LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                    ------ the parameter type `G` must be valid for the anonymous lifetime defined here...
+...
 LL | /     move || {
 LL | |
 LL | |
 LL | |         *dest = g.get();
 LL | |     }
-   | |_____^
-   |
-note: the parameter type `G` must be valid for the anonymous lifetime defined here...
-  --> $DIR/missing-lifetimes-in-signature.rs:69:34
-   |
-LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-   |                                  ^^^^^^
-note: ...so that the type `G` will meet its required lifetime bounds
-  --> $DIR/missing-lifetimes-in-signature.rs:73:5
+   | |_____^ ...so that the type `G` will meet its required lifetime bounds
    |
-LL | /     move || {
-LL | |
-LL | |
-LL | |         *dest = g.get();
-LL | |     }
-   | |_____^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
-LL | fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + '_ + 'a
-   |        +++           ++++                  ++
+LL | fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + 'b + 'a
+   |        +++           ++++                  ++                           ~~
 
 error[E0621]: explicit lifetime required in the type of `dest`
   --> $DIR/missing-lifetimes-in-signature.rs:73:5
@@ -153,13 +111,16 @@ LL | |     }
 error[E0309]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:85:5
    |
+LL |   fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+   |          -- the parameter type `G` must be valid for the lifetime `'a` as defined here...
+...
 LL | /     move || {
 LL | |
 LL | |         *dest = g.get();
 LL | |     }
    | |_____^ ...so that the type `G` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     G: Get<T> + 'a,
    |               ++++
diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed
new file mode 100644
index 00000000000..470cc67b973
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed
@@ -0,0 +1,47 @@
+// Make sure we suggest the bound `T: 'a` in the correct scope:
+// trait, impl or associated fn.
+// run-rustfix
+
+struct Inv<'a>(Option<*mut &'a u8>);
+
+fn check_bound<'a, A: 'a>(_: A, _: Inv<'a>) {}
+
+trait Trait1<'a>: Sized where Self: 'a {
+    fn foo(self, lt: Inv<'a>) {
+        check_bound(self, lt)
+        //~^ ERROR parameter type `Self` may not live long enough
+    }
+}
+
+trait Trait2: Sized {
+    fn foo<'a>(self, lt: Inv<'a>) where Self: 'a {
+        check_bound(self, lt)
+        //~^ ERROR parameter type `Self` may not live long enough
+    }
+}
+
+trait Trait3<T> {
+    fn foo<'a>(arg: T, lt: Inv<'a>) where T: 'a {
+        check_bound(arg, lt)
+        //~^ ERROR parameter type `T` may not live long enough
+    }
+}
+
+trait Trait4<'a> {
+    fn foo<T: 'a>(arg: T, lt: Inv<'a>) {
+        check_bound(arg, lt)
+        //~^ ERROR parameter type `T` may not live long enough
+    }
+}
+
+trait Trait5<'a> {
+    fn foo(self, _: Inv<'a>);
+}
+impl<'a, T: 'a> Trait5<'a> for T {
+    fn foo(self, lt: Inv<'a>) {
+        check_bound(self, lt);
+        //~^ ERROR parameter type `T` may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs
new file mode 100644
index 00000000000..874788e13ef
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs
@@ -0,0 +1,47 @@
+// Make sure we suggest the bound `T: 'a` in the correct scope:
+// trait, impl or associated fn.
+// run-rustfix
+
+struct Inv<'a>(Option<*mut &'a u8>);
+
+fn check_bound<'a, A: 'a>(_: A, _: Inv<'a>) {}
+
+trait Trait1<'a>: Sized {
+    fn foo(self, lt: Inv<'a>) {
+        check_bound(self, lt)
+        //~^ ERROR parameter type `Self` may not live long enough
+    }
+}
+
+trait Trait2: Sized {
+    fn foo<'a>(self, lt: Inv<'a>) {
+        check_bound(self, lt)
+        //~^ ERROR parameter type `Self` may not live long enough
+    }
+}
+
+trait Trait3<T> {
+    fn foo<'a>(arg: T, lt: Inv<'a>) {
+        check_bound(arg, lt)
+        //~^ ERROR parameter type `T` may not live long enough
+    }
+}
+
+trait Trait4<'a> {
+    fn foo<T>(arg: T, lt: Inv<'a>) {
+        check_bound(arg, lt)
+        //~^ ERROR parameter type `T` may not live long enough
+    }
+}
+
+trait Trait5<'a> {
+    fn foo(self, _: Inv<'a>);
+}
+impl<'a, T> Trait5<'a> for T {
+    fn foo(self, lt: Inv<'a>) {
+        check_bound(self, lt);
+        //~^ ERROR parameter type `T` may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr
new file mode 100644
index 00000000000..d3ca2cc1162
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr
@@ -0,0 +1,71 @@
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/type-param-bound-scope.rs:11:9
+   |
+LL | trait Trait1<'a>: Sized {
+   |              -- the parameter type `Self` must be valid for the lifetime `'a` as defined here...
+LL |     fn foo(self, lt: Inv<'a>) {
+LL |         check_bound(self, lt)
+   |         ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `Self` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | trait Trait1<'a>: Sized where Self: 'a {
+   |                         ++++++++++++++
+
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/type-param-bound-scope.rs:18:9
+   |
+LL |     fn foo<'a>(self, lt: Inv<'a>) {
+   |            -- the parameter type `Self` must be valid for the lifetime `'a` as defined here...
+LL |         check_bound(self, lt)
+   |         ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `Self` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     fn foo<'a>(self, lt: Inv<'a>) where Self: 'a {
+   |                                   ++++++++++++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/type-param-bound-scope.rs:25:9
+   |
+LL |     fn foo<'a>(arg: T, lt: Inv<'a>) {
+   |            -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+LL |         check_bound(arg, lt)
+   |         ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     fn foo<'a>(arg: T, lt: Inv<'a>) where T: 'a {
+   |                                     +++++++++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/type-param-bound-scope.rs:32:9
+   |
+LL | trait Trait4<'a> {
+   |              -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+LL |     fn foo<T>(arg: T, lt: Inv<'a>) {
+LL |         check_bound(arg, lt)
+   |         ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     fn foo<T: 'a>(arg: T, lt: Inv<'a>) {
+   |             ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/type-param-bound-scope.rs:42:9
+   |
+LL | impl<'a, T> Trait5<'a> for T {
+   |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
+LL |     fn foo(self, lt: Inv<'a>) {
+LL |         check_bound(self, lt);
+   |         ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | impl<'a, T: 'a> Trait5<'a> for T {
+   |           ++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.fixed b/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.fixed
new file mode 100644
index 00000000000..e30c556457e
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.fixed
@@ -0,0 +1,52 @@
+// We want to suggest a bound `T: 'a` but `'a` is elided,
+// run-rustfix
+// edition: 2018
+#![allow(dead_code)]
+
+struct Inv<'a>(Option<*mut &'a u8>);
+
+fn check_bound<'a, A: 'a>(_: A, _: Inv<'a>) {}
+
+struct Elided<'a, T = ()>(Inv<'a>, T);
+
+struct MyTy<X>(X);
+
+impl<'a, X> MyTy<Elided<'a, X>> {
+    async fn foo<A: 'a>(self, arg: A, _: &str) -> &str {
+        check_bound(arg, self.0 .0);
+        //~^ ERROR parameter type `A` may not live long enough
+        ""
+    }
+}
+
+// Make sure the new lifetime name doesn't conflict with
+// other early- or late-bound lifetimes in-scope.
+impl<'a, A> MyTy<(A, &'a ())> {
+    async fn foo2<'b>(
+        arg: A,
+        lt: Inv<'b>,
+    ) -> (
+        impl Into<&'b str> + Into<&'b str> + 'b,
+        impl Into<Option<Elided<'b>>> + 'b,
+        impl Into<Option<Elided<'b, ()>>>,
+    ) where A: 'b {
+        check_bound(arg, lt);
+        //~^ ERROR parameter type `A` may not live long enough
+        ("", None, None)
+    }
+
+    // same as above but there is a late-bound lifetime named `'b`.
+    async fn bar2<'c, 'b>(_dummy: &'a u8, arg: A, lt: Inv<'c>) where A: 'c {
+        check_bound(arg, lt);
+        //~^ ERROR parameter type `A` may not live long enough
+    }
+}
+
+impl<'a, A: 'a> MyTy<Elided<'a, A>> {
+    async fn foo3(self) {
+        check_bound(self.0 .1, self.0 .0);
+        //~^ ERROR parameter type `A` may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.rs b/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.rs
new file mode 100644
index 00000000000..85f08808b73
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.rs
@@ -0,0 +1,52 @@
+// We want to suggest a bound `T: 'a` but `'a` is elided,
+// run-rustfix
+// edition: 2018
+#![allow(dead_code)]
+
+struct Inv<'a>(Option<*mut &'a u8>);
+
+fn check_bound<'a, A: 'a>(_: A, _: Inv<'a>) {}
+
+struct Elided<'a, T = ()>(Inv<'a>, T);
+
+struct MyTy<X>(X);
+
+impl<X> MyTy<Elided<'_, X>> {
+    async fn foo<A>(self, arg: A, _: &str) -> &str {
+        check_bound(arg, self.0 .0);
+        //~^ ERROR parameter type `A` may not live long enough
+        ""
+    }
+}
+
+// Make sure the new lifetime name doesn't conflict with
+// other early- or late-bound lifetimes in-scope.
+impl<'a, A> MyTy<(A, &'a ())> {
+    async fn foo2(
+        arg: A,
+        lt: Inv<'_>,
+    ) -> (
+        impl Into<&str> + Into<&'_ str> + '_,
+        impl Into<Option<Elided>> + '_,
+        impl Into<Option<Elided<()>>>,
+    ) {
+        check_bound(arg, lt);
+        //~^ ERROR parameter type `A` may not live long enough
+        ("", None, None)
+    }
+
+    // same as above but there is a late-bound lifetime named `'b`.
+    async fn bar2<'b>(_dummy: &'a u8, arg: A, lt: Inv<'_>) {
+        check_bound(arg, lt);
+        //~^ ERROR parameter type `A` may not live long enough
+    }
+}
+
+impl<A> MyTy<Elided<'_, A>> {
+    async fn foo3(self) {
+        check_bound(self.0 .1, self.0 .0);
+        //~^ ERROR parameter type `A` may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.stderr b/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.stderr
new file mode 100644
index 00000000000..2f74a006b3b
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/type-param-missing-lifetime.stderr
@@ -0,0 +1,66 @@
+error[E0311]: the parameter type `A` may not live long enough
+  --> $DIR/type-param-missing-lifetime.rs:16:9
+   |
+LL | impl<X> MyTy<Elided<'_, X>> {
+   |                     -- the parameter type `A` must be valid for the anonymous lifetime as defined here...
+LL |     async fn foo<A>(self, arg: A, _: &str) -> &str {
+LL |         check_bound(arg, self.0 .0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL ~ impl<'a, X> MyTy<Elided<'a, X>> {
+LL ~     async fn foo<A: 'a>(self, arg: A, _: &str) -> &str {
+   |
+
+error[E0311]: the parameter type `A` may not live long enough
+  --> $DIR/type-param-missing-lifetime.rs:33:9
+   |
+LL |         lt: Inv<'_>,
+   |             ------- the parameter type `A` must be valid for the anonymous lifetime defined here...
+...
+LL |         check_bound(arg, lt);
+   |         ^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL ~     async fn foo2<'b>(
+LL |         arg: A,
+LL ~         lt: Inv<'b>,
+LL |     ) -> (
+LL ~         impl Into<&'b str> + Into<&'b str> + 'b,
+LL ~         impl Into<Option<Elided<'b>>> + 'b,
+LL ~         impl Into<Option<Elided<'b, ()>>>,
+LL ~     ) where A: 'b {
+   |
+
+error[E0311]: the parameter type `A` may not live long enough
+  --> $DIR/type-param-missing-lifetime.rs:40:9
+   |
+LL |     async fn bar2<'b>(_dummy: &'a u8, arg: A, lt: Inv<'_>) {
+   |                                                   ------- the parameter type `A` must be valid for the anonymous lifetime defined here...
+LL |         check_bound(arg, lt);
+   |         ^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     async fn bar2<'c, 'b>(_dummy: &'a u8, arg: A, lt: Inv<'c>) where A: 'c {
+   |                   +++                                     ~~   +++++++++++
+
+error[E0311]: the parameter type `A` may not live long enough
+  --> $DIR/type-param-missing-lifetime.rs:47:9
+   |
+LL | impl<A> MyTy<Elided<'_, A>> {
+   |                     -- the parameter type `A` must be valid for the anonymous lifetime as defined here...
+LL |     async fn foo3(self) {
+LL |         check_bound(self.0 .1, self.0 .0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | impl<'a, A: 'a> MyTy<Elided<'a, A>> {
+   |      +++  ++++              ~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
diff --git a/tests/ui/suggestions/suggest-impl-trait-lifetime.fixed b/tests/ui/suggestions/suggest-impl-trait-lifetime.fixed
index 589ee1a474a..4f2fd5ba600 100644
--- a/tests/ui/suggestions/suggest-impl-trait-lifetime.fixed
+++ b/tests/ui/suggestions/suggest-impl-trait-lifetime.fixed
@@ -3,9 +3,10 @@
 use std::fmt::Debug;
 
 fn foo(d: impl Debug + 'static) {
-//~^ HELP consider adding an explicit lifetime bound...
+//~^ HELP consider adding an explicit lifetime bound
     bar(d);
 //~^ ERROR the parameter type `impl Debug` may not live long enough
+//~| NOTE the parameter type `impl Debug` must be valid for the static lifetime...
 //~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds
 }
 
diff --git a/tests/ui/suggestions/suggest-impl-trait-lifetime.rs b/tests/ui/suggestions/suggest-impl-trait-lifetime.rs
index 9a87129fbf2..a266e360edb 100644
--- a/tests/ui/suggestions/suggest-impl-trait-lifetime.rs
+++ b/tests/ui/suggestions/suggest-impl-trait-lifetime.rs
@@ -3,9 +3,10 @@
 use std::fmt::Debug;
 
 fn foo(d: impl Debug) {
-//~^ HELP consider adding an explicit lifetime bound...
+//~^ HELP consider adding an explicit lifetime bound
     bar(d);
 //~^ ERROR the parameter type `impl Debug` may not live long enough
+//~| NOTE the parameter type `impl Debug` must be valid for the static lifetime...
 //~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds
 }
 
diff --git a/tests/ui/suggestions/suggest-impl-trait-lifetime.stderr b/tests/ui/suggestions/suggest-impl-trait-lifetime.stderr
index cf912f4aac2..1660db1aa83 100644
--- a/tests/ui/suggestions/suggest-impl-trait-lifetime.stderr
+++ b/tests/ui/suggestions/suggest-impl-trait-lifetime.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `impl Debug` may not live long enough
   --> $DIR/suggest-impl-trait-lifetime.rs:7:5
    |
 LL |     bar(d);
-   |     ^^^^^^ ...so that the type `impl Debug` will meet its required lifetime bounds
+   |     ^^^^^^
+   |     |
+   |     the parameter type `impl Debug` must be valid for the static lifetime...
+   |     ...so that the type `impl Debug` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | fn foo(d: impl Debug + 'static) {
    |                      +++++++++
diff --git a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr
index b114d295d78..63280b8616f 100644
--- a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr
+++ b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr
@@ -12,8 +12,11 @@ LL + use std::borrow::Cow;
 error[E0119]: conflicting implementations of trait `From<LabelText>` for type `LabelText`
   --> $DIR/impl-bound-with-references-error.rs:9:1
    |
-LL | impl<T> From<T> for LabelText
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl<T> From<T> for LabelText
+LL | |
+LL | | where
+LL | |     T: Into<Cow<'static, str>>,
+   | |_______________________________^
    |
    = note: conflicting implementation in crate `core`:
            - impl<T> From<T> for T;
diff --git a/tests/ui/traits/issue-33140-hack-boundaries.stderr b/tests/ui/traits/issue-33140-hack-boundaries.stderr
index 80a502c6335..06e1dfd3727 100644
--- a/tests/ui/traits/issue-33140-hack-boundaries.stderr
+++ b/tests/ui/traits/issue-33140-hack-boundaries.stderr
@@ -60,7 +60,7 @@ error[E0119]: conflicting implementations of trait `Trait5` for type `(dyn Send
 LL | impl Trait5 for dyn Send {}
    | ------------------------ first implementation here
 LL | impl Trait5 for dyn Send where u32: Copy {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.stderr b/tests/ui/traits/new-solver/coherence/issue-102048.stderr
index 17a43838fe2..41bf68a1d9f 100644
--- a/tests/ui/traits/new-solver/coherence/issue-102048.stderr
+++ b/tests/ui/traits/new-solver/coherence/issue-102048.stderr
@@ -1,11 +1,15 @@
 error[E0119]: conflicting implementations of trait `Trait<for<'a> fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)`
   --> $DIR/issue-102048.rs:39:1
    |
-LL | impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U)
-   | --------------------------------------------------------------------------------------------------- first implementation here
+LL | / impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U)
+LL | | where
+LL | |     T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>,
+LL | |     U: for<'a> WithAssoc2<'a>,
+   | |______________________________- first implementation here
 ...
-LL | impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)`
+LL | / impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where
+LL | |     U: for<'a> WithAssoc1<'a>
+   | |_____________________________^ conflicting implementation for `(_, _)`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs b/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs
new file mode 100644
index 00000000000..d67fc65032c
--- /dev/null
+++ b/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+
+trait Foo {
+    fn test() -> impl Fn(u32) -> u32 {
+        |x| x.count_ones()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr b/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr
index 7ad495a35e0..368f5cd0c3b 100644
--- a/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr
+++ b/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr
@@ -13,7 +13,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `()`
 LL | impl Foo for () {}
    | --------------- first implementation here
 LL | impl<T> Foo for T where T: Bar<ASSOC = 0> {}
-   | ^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs b/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs
new file mode 100644
index 00000000000..b6200096a89
--- /dev/null
+++ b/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs
@@ -0,0 +1,11 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+
+trait Foo {
+    async fn bar() {}
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
index ae6462bb62c..3484485e3fd 100644
--- a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
+++ b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
@@ -46,14 +46,17 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/closure_wf_outlives.rs:54:22
    |
 LL |     type Opaque<T> = impl Sized;
-   |                      ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |                      ^^^^^^^^^^
+   |                      |
+   |                      the parameter type `T` must be valid for the static lifetime...
+   |                      ...so that the type `T` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
   --> $DIR/closure_wf_outlives.rs:59:12
    |
 LL |         T: 'static,
    |            ^^^^^^^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     type Opaque<T: 'static> = impl Sized;
    |                  +++++++++
diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
index 8c3a25dbfe7..c352a33fbbc 100644
--- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
@@ -17,9 +17,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:13:9
    |
 LL |         t
-   |         ^ ...so that the type `T` will meet its required lifetime bounds
+   |         ^
+   |         |
+   |         the parameter type `T` must be valid for the static lifetime...
+   |         ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
    |                       +++++++++
diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
index 399775641f8..d6dd20739b7 100644
--- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
+++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
@@ -22,9 +22,12 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/implied_lifetime_wf_check3.rs:29:41
    |
 LL |     fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
-   |                                         ^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |                                         ^^^^^^^^^^^^^^^^^^
+   |                                         |
+   |                                         the parameter type `A` must be valid for the static lifetime...
+   |                                         ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     fn test<A: 'static>() where Ty<A>: 'static { assert_static::<A>() }
    |              +++++++++
diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
index 47bc31e78c3..81bc64bc32c 100644
--- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
+++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/implied_lifetime_wf_check4_static.rs:4:18
    |
 LL |     type Ty<A> = impl Sized + 'static;
-   |                  ^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |                  ^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  the parameter type `A` must be valid for the static lifetime...
+   |                  ...so that the type `A` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     type Ty<A: 'static> = impl Sized + 'static;
    |              +++++++++
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
new file mode 100644
index 00000000000..4b09a9e743b
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
@@ -0,0 +1,20 @@
+error: internal compiler error: no errors encountered even though `delay_span_bug` issued
+
+error: internal compiler error: ambiguity performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(get_rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }))), bound_vars: [] } } }
+  --> $DIR/rpit_tait_equality_in_canonical_query.rs:28:5
+   |
+LL |     query(get_rpit);
+   |     ^^^^^^^^^^^^^^^
+   |
+  --> $DIR/rpit_tait_equality_in_canonical_query.rs:28:5
+   |
+LL |     query(get_rpit);
+   |     ^^^^^^^^^^^^^^^
+
+
+
+
+query stack during panic:
+end of query stack
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
index eefe333da45..8dccd2ed46f 100644
--- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
+++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
@@ -7,7 +7,14 @@
 
 // revisions: current next
 //[next] compile-flags: -Ztrait-solver=next
-// check-pass
+//[next] check-pass
+
+//[current] known-bug: #108498
+//[current] failure-status: 101
+//[current] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId("
+//[current] normalize-stderr-test: "(?m)^note: .*\n" -> ""
+//[current] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> ""
+//[current] normalize-stderr-test: "(?m)^ *at .*\n" -> ""
 
 #![feature(type_alias_impl_trait)]
 
diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
index 9e96323ab54..7d72c9f811a 100644
--- a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
+++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-associated-type.rs:36:23
    |
+LL |     impl<'a, T> Trait<'a, T> for () {
+   |          -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |         type Opaque = impl Sized + 'a;
    |                       ^^^^^^^^^^^^^^^ ...so that the type `&'a T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     impl<'a, T: 'a> Trait<'a, T> for () {
    |               ++++
@@ -12,10 +14,12 @@ LL |     impl<'a, T: 'a> Trait<'a, T> for () {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-associated-type.rs:36:23
    |
+LL |     impl<'a, T> Trait<'a, T> for () {
+   |          -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |         type Opaque = impl Sized + 'a;
    |                       ^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     impl<'a, T: 'a> Trait<'a, T> for () {
    |               ++++
diff --git a/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
index 753a46e882e..2858afcd46f 100644
--- a/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
+++ b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
@@ -2,14 +2,17 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-nested.rs:55:27
    |
 LL |     type InnerOpaque<T> = impl Sized;
-   |                           ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |                           ^^^^^^^^^^
+   |                           |
+   |                           the parameter type `T` must be valid for the static lifetime...
+   |                           ...so that the type `T` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
   --> $DIR/wf-nested.rs:12:20
    |
 LL | struct IsStatic<T: 'static>(T);
    |                    ^^^^^^^
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     type InnerOpaque<T: 'static> = impl Sized;
    |                       +++++++++
diff --git a/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr b/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
index 9ab6685a7f7..285e4f18ca3 100644
--- a/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
+++ b/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-nested.rs:46:17
    |
 LL |         let _ = outer.get();
-   |                 ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |                 ^^^^^^^^^^^
+   |                 |
+   |                 the parameter type `T` must be valid for the static lifetime...
+   |                 ...so that the type `T` will meet its required lifetime bounds
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL |     fn test<T: 'static>() {
    |              +++++++++
diff --git a/tests/ui/typeck/escaping_bound_vars.rs b/tests/ui/typeck/escaping_bound_vars.rs
new file mode 100644
index 00000000000..1fb063d2c26
--- /dev/null
+++ b/tests/ui/typeck/escaping_bound_vars.rs
@@ -0,0 +1,16 @@
+// Test for issues/115517 which is fixed by pull/115486
+// This should not ice
+trait Test<const C: usize> {}
+
+trait Elide<T> {
+    fn call();
+}
+
+pub fn test()
+where
+    (): Test<{ 1 + (<() as Elide(&())>::call) }>,
+    //~^ ERROR cannot capture late-bound lifetime in constant
+{
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/escaping_bound_vars.stderr b/tests/ui/typeck/escaping_bound_vars.stderr
new file mode 100644
index 00000000000..f7077e52a70
--- /dev/null
+++ b/tests/ui/typeck/escaping_bound_vars.stderr
@@ -0,0 +1,10 @@
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/escaping_bound_vars.rs:11:35
+   |
+LL |     (): Test<{ 1 + (<() as Elide(&())>::call) }>,
+   |                                  -^
+   |                                  |
+   |                                  lifetime defined here
+
+error: aborting due to previous error
+
diff --git a/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs
new file mode 100644
index 00000000000..c319c63eda2
--- /dev/null
+++ b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs
@@ -0,0 +1,96 @@
+// Regression test for ICE #116473.
+// The ICE occurs when arguments are specified on an enum variant
+// (which is illegal) and the variant and its preceding path are
+// located at different places such as in different macros or
+// different expansions of the same macro (i.e. when the macro
+// calls itself recursively)
+
+enum Enum<T1, T2> {  VariantA { _v1: T1, _v2: T2 }, VariantB }
+
+type EnumUnit = Enum<(), ()>;
+
+// Recursive macro call using a tt metavariable for variant
+macro_rules! recursive_tt {
+    () => (recursive_tt!(VariantB));
+    ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+}
+
+
+// Recursive macro call using an ident metavariable for variant
+// (the behaviour is different for tt and ident)
+macro_rules! recursive_ident {
+    () => (recursive_ident!(VariantB));
+    ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+}
+
+
+// Mested macro calls (i.e. one calling another) using a tt
+// metavariable for variant
+macro_rules! nested1_tt {
+    () => (nested2_tt!(VariantB));
+}
+
+macro_rules! nested2_tt {
+    ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+}
+
+
+// Mested macro calls using an ident metavariable for variant
+// (the behaviour is different for tt and ident)
+macro_rules! nested1_ident {
+    () => (nested2_ident!(VariantB));
+}
+
+macro_rules! nested2_ident {
+    ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+}
+
+
+// Mested macro calls when args are passed as metavariable
+// instead of the enum variant
+macro_rules! nested1_tt_args_in_first_macro {
+    () => (nested2_tt_args_in_first_macro!(i32, u32));
+}
+
+macro_rules! nested2_tt_args_in_first_macro {
+    ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+            = 5 { true } else { false });
+}
+
+// Mested macro calls when args are passed as metavariable
+// instead of the enum variant
+macro_rules! nested1_ident_args_in_first_macro {
+    () => (nested2_ident_args_in_first_macro!(i32, u32));
+}
+
+macro_rules! nested2_ident_args_in_first_macro {
+    ($arg1:ident, $arg2:ident) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+        = 5 { true } else { false });
+}
+
+fn main() {
+    // Macro cases
+    recursive_tt!();
+    recursive_ident!();
+    nested1_tt!();
+    nested1_ident!();
+    nested1_tt_args_in_first_macro!();
+    nested1_ident_args_in_first_macro!();
+
+    // Regular, non-macro case
+    if let EnumUnit::VariantB::<i32, u32> {} = 5 { true } else { false };
+    //~^ ERROR type arguments are not allowed on this type
+    //~| ERROR mismatched types
+}
diff --git a/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr
new file mode 100644
index 00000000000..437800f1181
--- /dev/null
+++ b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr
@@ -0,0 +1,255 @@
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:15:51
+   |
+LL |     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                                        --------   ^^^  ^^^ type argument not allowed
+   |                                        |
+   |                                        not allowed on this type
+...
+LL |     recursive_tt!();
+   |     ---------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: enum variants can't have type parameters
+   = note: this error originates in the macro `recursive_tt` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+LL +     ($variant:tt) => (if let EnumUnit::<i32, u32>::$variant {} = 5 { true } else { false });
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:15:30
+   |
+LL |     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `{integer}`
+   |                              |
+   |                              expected integer, found `Enum<(), ()>`
+...
+LL |     recursive_tt!();
+   |     --------------- in this macro invocation
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+   = note: this error originates in the macro `recursive_tt` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:25:54
+   |
+LL |     () => (recursive_ident!(VariantB));
+   |                             -------- not allowed on this type
+LL |     ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                                                      ^^^  ^^^ type argument not allowed
+...
+LL |     recursive_ident!();
+   |     ------------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: enum variants can't have type parameters
+   = note: this error originates in the macro `recursive_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+LL +     ($variant:ident) => (if let EnumUnit::<i32, u32>::$variant {} = 5 { true } else { false });
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:25:33
+   |
+LL |     ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `{integer}`
+   |                                 |
+   |                                 expected integer, found `Enum<(), ()>`
+...
+LL |     recursive_ident!();
+   |     ------------------ in this macro invocation
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+   = note: this error originates in the macro `recursive_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:38:51
+   |
+LL |     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                                        --------   ^^^  ^^^ type argument not allowed
+   |                                        |
+   |                                        not allowed on this type
+...
+LL |     nested1_tt!();
+   |     -------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: enum variants can't have type parameters
+   = note: this error originates in the macro `nested2_tt` which comes from the expansion of the macro `nested1_tt` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+LL +     ($variant:tt) => (if let EnumUnit::<i32, u32>::$variant {} = 5 { true } else { false });
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:38:30
+   |
+LL |     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `{integer}`
+   |                              |
+   |                              expected integer, found `Enum<(), ()>`
+...
+LL |     nested1_tt!();
+   |     ------------- in this macro invocation
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+   = note: this error originates in the macro `nested2_tt` which comes from the expansion of the macro `nested1_tt` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:51:54
+   |
+LL |     () => (nested2_ident!(VariantB));
+   |                           -------- not allowed on this type
+...
+LL |     ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                                                      ^^^  ^^^ type argument not allowed
+...
+LL |     nested1_ident!();
+   |     ----------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: enum variants can't have type parameters
+   = note: this error originates in the macro `nested2_ident` which comes from the expansion of the macro `nested1_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+LL +     ($variant:ident) => (if let EnumUnit::<i32, u32>::$variant {} = 5 { true } else { false });
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:51:33
+   |
+LL |     ($variant:ident) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `{integer}`
+   |                                 |
+   |                                 expected integer, found `Enum<(), ()>`
+...
+LL |     nested1_ident!();
+   |     ---------------- in this macro invocation
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+   = note: this error originates in the macro `nested2_ident` which comes from the expansion of the macro `nested1_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:64:58
+   |
+LL |     ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+   |                                               --------   ^^^^^  ^^^^^ type argument not allowed
+   |                                               |
+   |                                               not allowed on this type
+...
+LL |     nested1_tt_args_in_first_macro!();
+   |     ---------------------------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: enum variants can't have type parameters
+   = note: this error originates in the macro `nested1_tt_args_in_first_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+LL +     ($arg1:tt, $arg2:tt) => (if let EnumUnit::<$arg1, $arg2>::VariantB {}
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:64:37
+   |
+LL |     ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected integer, found `Enum<(), ()>`
+...
+LL |             = 5 { true } else { false });
+   |               - this expression has type `{integer}`
+...
+LL |     nested1_tt_args_in_first_macro!();
+   |     --------------------------------- in this macro invocation
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+   = note: this error originates in the macro `nested2_tt_args_in_first_macro` which comes from the expansion of the macro `nested1_tt_args_in_first_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:77:64
+   |
+LL |     ($arg1:ident, $arg2:ident) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+   |                                                     --------   ^^^^^  ^^^^^ type argument not allowed
+   |                                                     |
+   |                                                     not allowed on this type
+...
+LL |     nested1_ident_args_in_first_macro!();
+   |     ------------------------------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: enum variants can't have type parameters
+   = note: this error originates in the macro `nested2_ident_args_in_first_macro` which comes from the expansion of the macro `nested1_ident_args_in_first_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     ($arg1:ident, $arg2:ident) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+LL +     ($arg1:ident, $arg2:ident) => (if let EnumUnit::<$arg1, $arg2>::VariantB {}
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:77:43
+   |
+LL |     ($arg1:ident, $arg2:ident) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected integer, found `Enum<(), ()>`
+...
+LL |         = 5 { true } else { false });
+   |           - this expression has type `{integer}`
+...
+LL |     nested1_ident_args_in_first_macro!();
+   |     ------------------------------------ in this macro invocation
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+   = note: this error originates in the macro `nested2_ident_args_in_first_macro` which comes from the expansion of the macro `nested1_ident_args_in_first_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0109]: type arguments are not allowed on this type
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:93:33
+   |
+LL |     if let EnumUnit::VariantB::<i32, u32> {} = 5 { true } else { false };
+   |                      --------   ^^^  ^^^ type argument not allowed
+   |                      |
+   |                      not allowed on this type
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specify type parameters on enum `Enum`
+   |
+LL -     if let EnumUnit::VariantB::<i32, u32> {} = 5 { true } else { false };
+LL +     if let EnumUnit::<i32, u32>::VariantB {} = 5 { true } else { false };
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:93:12
+   |
+LL |     if let EnumUnit::VariantB::<i32, u32> {} = 5 { true } else { false };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `{integer}`
+   |            |
+   |            expected integer, found `Enum<(), ()>`
+   |
+   = note: expected type `{integer}`
+              found enum `Enum<(), ()>`
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0109, E0308.
+For more information about an error, try `rustc --explain E0109`.
diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs
index 9f76849e5fb..0999f61b01a 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs
+++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs
@@ -1,7 +1,35 @@
 use std::ops::FnMut;
 
-pub fn main() {
+fn main() {
     let mut f = |x: isize, y: isize| -> isize { x + y };
-    let z = f(1_usize, 2);    //~ ERROR mismatched types
+    let z = f(1_usize, 2); //~ ERROR mismatched types
     println!("{}", z);
+    let mut g = |x, y| { x + y };
+    let y = g(1_i32, 2);
+    let z = g(1_usize, 2); //~ ERROR mismatched types
+    println!("{}", z);
+}
+
+trait T {
+    fn bar(&self) {
+        let identity = |x| x;
+        identity(1u8);
+        identity(1u16); //~ ERROR mismatched types
+        let identity = |x| x;
+        identity(&1u8);
+        identity(&1u16); //~ ERROR mismatched types
+    }
+}
+
+struct S;
+
+impl T  for S {
+    fn bar(&self) {
+        let identity = |x| x;
+        identity(1u8);
+        identity(1u16); //~ ERROR mismatched types
+        let identity = |x| x;
+        identity(&1u8);
+        identity(&1u16); //~ ERROR mismatched types
+    }
 }
diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr
index 455f83f5721..327df50e645 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr
@@ -16,6 +16,127 @@ help: change the type of the numeric literal from `usize` to `isize`
 LL |     let z = f(1_isize, 2);
    |                 ~~~~~
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/unboxed-closures-type-mismatch.rs:9:15
+   |
+LL |     let z = g(1_usize, 2);
+   |             - ^^^^^^^ expected `i32`, found `usize`
+   |             |
+   |             arguments to this function are incorrect
+   |
+note: expected because the closure was earlier called with an argument of type `i32`
+  --> $DIR/unboxed-closures-type-mismatch.rs:8:15
+   |
+LL |     let y = g(1_i32, 2);
+   |             - ^^^^^ expected because this argument is of type `i32`
+   |             |
+   |             in this closure call
+note: closure parameter defined here
+  --> $DIR/unboxed-closures-type-mismatch.rs:7:18
+   |
+LL |     let mut g = |x, y| { x + y };
+   |                  ^
+help: change the type of the numeric literal from `usize` to `i32`
+   |
+LL |     let z = g(1_i32, 2);
+   |                 ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/unboxed-closures-type-mismatch.rs:17:18
+   |
+LL |         identity(1u16);
+   |         -------- ^^^^ expected `u8`, found `u16`
+   |         |
+   |         arguments to this function are incorrect
+   |
+note: expected because the closure was earlier called with an argument of type `u8`
+  --> $DIR/unboxed-closures-type-mismatch.rs:16:18
+   |
+LL |         identity(1u8);
+   |         -------- ^^^ expected because this argument is of type `u8`
+   |         |
+   |         in this closure call
+note: closure parameter defined here
+  --> $DIR/unboxed-closures-type-mismatch.rs:15:25
+   |
+LL |         let identity = |x| x;
+   |                         ^
+help: change the type of the numeric literal from `u16` to `u8`
+   |
+LL |         identity(1u8);
+   |                   ~~
+
+error[E0308]: mismatched types
+  --> $DIR/unboxed-closures-type-mismatch.rs:20:18
+   |
+LL |         identity(&1u16);
+   |         -------- ^^^^^ expected `&u8`, found `&u16`
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected reference `&u8`
+              found reference `&u16`
+note: expected because the closure was earlier called with an argument of type `&u8`
+  --> $DIR/unboxed-closures-type-mismatch.rs:19:18
+   |
+LL |         identity(&1u8);
+   |         -------- ^^^^ expected because this argument is of type `&u8`
+   |         |
+   |         in this closure call
+note: closure parameter defined here
+  --> $DIR/unboxed-closures-type-mismatch.rs:18:25
+   |
+LL |         let identity = |x| x;
+   |                         ^
+
+error[E0308]: mismatched types
+  --> $DIR/unboxed-closures-type-mismatch.rs:30:18
+   |
+LL |         identity(1u16);
+   |         -------- ^^^^ expected `u8`, found `u16`
+   |         |
+   |         arguments to this function are incorrect
+   |
+note: expected because the closure was earlier called with an argument of type `u8`
+  --> $DIR/unboxed-closures-type-mismatch.rs:29:18
+   |
+LL |         identity(1u8);
+   |         -------- ^^^ expected because this argument is of type `u8`
+   |         |
+   |         in this closure call
+note: closure parameter defined here
+  --> $DIR/unboxed-closures-type-mismatch.rs:28:25
+   |
+LL |         let identity = |x| x;
+   |                         ^
+help: change the type of the numeric literal from `u16` to `u8`
+   |
+LL |         identity(1u8);
+   |                   ~~
+
+error[E0308]: mismatched types
+  --> $DIR/unboxed-closures-type-mismatch.rs:33:18
+   |
+LL |         identity(&1u16);
+   |         -------- ^^^^^ expected `&u8`, found `&u16`
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected reference `&u8`
+              found reference `&u16`
+note: expected because the closure was earlier called with an argument of type `&u8`
+  --> $DIR/unboxed-closures-type-mismatch.rs:32:18
+   |
+LL |         identity(&1u8);
+   |         -------- ^^^^ expected because this argument is of type `&u8`
+   |         |
+   |         in this closure call
+note: closure parameter defined here
+  --> $DIR/unboxed-closures-type-mismatch.rs:31:25
+   |
+LL |         let identity = |x| x;
+   |                         ^
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/wf/wf-impl-associated-type-region.stderr b/tests/ui/wf/wf-impl-associated-type-region.stderr
index b9d4857a3ef..e6fb81247ad 100644
--- a/tests/ui/wf/wf-impl-associated-type-region.stderr
+++ b/tests/ui/wf/wf-impl-associated-type-region.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-impl-associated-type-region.rs:10:16
    |
+LL | impl<'a, T> Foo<'a> for T {
+   |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     type Bar = &'a T;
    |                ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<'a, T: 'a> Foo<'a> for T {
    |           ++++
diff --git a/tests/ui/wf/wf-in-fn-type-static.stderr b/tests/ui/wf/wf-in-fn-type-static.stderr
index 73fbb9ca670..45ad9fba0ce 100644
--- a/tests/ui/wf/wf-in-fn-type-static.stderr
+++ b/tests/ui/wf/wf-in-fn-type-static.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-fn-type-static.rs:13:8
    |
 LL |     x: fn() -> &'static T
-   |        ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^^^^^
+   |        |
+   |        the parameter type `T` must be valid for the static lifetime...
+   |        ...so that the reference type `&'static T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | struct Foo<T: 'static> {
    |             +++++++++
@@ -13,9 +16,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-fn-type-static.rs:18:8
    |
 LL |     x: fn(&'static T)
-   |        ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^
+   |        |
+   |        the parameter type `T` must be valid for the static lifetime...
+   |        ...so that the reference type `&'static T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | struct Bar<T: 'static> {
    |             +++++++++
diff --git a/tests/ui/wf/wf-in-obj-type-static.stderr b/tests/ui/wf/wf-in-obj-type-static.stderr
index c3ad42dd5d5..4b9b189164c 100644
--- a/tests/ui/wf/wf-in-obj-type-static.stderr
+++ b/tests/ui/wf/wf-in-obj-type-static.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-obj-type-static.rs:14:8
    |
 LL |     x: dyn Object<&'static T>
-   |        ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^^^^^^^^^
+   |        |
+   |        the parameter type `T` must be valid for the static lifetime...
+   |        ...so that the reference type `&'static T` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | struct Foo<T: 'static> {
    |             +++++++++
diff --git a/tests/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr b/tests/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
index 4d4d8b2ab4d..e0cf42fd10c 100644
--- a/tests/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
+++ b/tests/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
@@ -1,10 +1,12 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:16
    |
+LL | impl<'a, T> Trait<'a, T> for usize {
+   |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     type Out = &'a fn(T);
    |                ^^^^^^^^^ ...so that the reference type `&'a fn(T)` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<'a, T: 'a> Trait<'a, T> for usize {
    |           ++++
@@ -12,10 +14,12 @@ LL | impl<'a, T: 'a> Trait<'a, T> for usize {
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:16
    |
+LL | impl<'a, T> Trait<'a, T> for u32 {
+   |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
 LL |     type Out = &'a dyn Baz<T>;
    |                ^^^^^^^^^^^^^^ ...so that the reference type `&'a (dyn Baz<T> + 'a)` does not outlive the data it points at
    |
-help: consider adding an explicit lifetime bound...
+help: consider adding an explicit lifetime bound
    |
 LL | impl<'a, T: 'a> Trait<'a, T> for u32 {
    |           ++++
diff --git a/tests/ui/wf/wf-trait-associated-type-region.stderr b/tests/ui/wf/wf-trait-associated-type-region.stderr
index 6e2cc8aba4b..ca7aeb55b25 100644
--- a/tests/ui/wf/wf-trait-associated-type-region.stderr
+++ b/tests/ui/wf/wf-trait-associated-type-region.stderr
@@ -1,11 +1,16 @@
 error[E0309]: the associated type `<Self as SomeTrait<'a>>::Type1` may not live long enough
   --> $DIR/wf-trait-associated-type-region.rs:9:18
    |
+LL | trait SomeTrait<'a> {
+   |                 -- the associated type `<Self as SomeTrait<'a>>::Type1` must be valid for the lifetime `'a` as defined here...
+LL |     type Type1;
 LL |     type Type2 = &'a Self::Type1;
-   |                  ^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^ ...so that the reference type `&'a <Self as SomeTrait<'a>>::Type1` does not outlive the data it points at
    |
-   = help: consider adding an explicit lifetime bound `<Self as SomeTrait<'a>>::Type1: 'a`...
-   = note: ...so that the reference type `&'a <Self as SomeTrait<'a>>::Type1` does not outlive the data it points at
+help: consider adding an explicit lifetime bound
+   |
+LL |     type Type2 = &'a Self::Type1 where <Self as SomeTrait<'a>>::Type1: 'a;
+   |                                  ++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error