about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/dependencies.yml9
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs20
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/coverageinfo.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs41
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs39
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/size_of_val.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs58
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs14
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs20
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs25
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs25
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs12
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs24
-rw-r--r--compiler/rustc_errors/src/emitter.rs3
-rw-r--r--compiler/rustc_errors/src/lib.rs8
-rw-r--r--compiler/rustc_hir/src/hir.rs16
-rw-r--r--compiler/rustc_hir/src/intravisit.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs22
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_infer/messages.ftl2
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs13
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs7
-rw-r--r--compiler/rustc_interface/src/interface.rs2
-rw-r--r--compiler/rustc_lexer/src/cursor.rs11
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/late.rs2
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs4
-rw-r--r--compiler/rustc_lint/src/passes.rs2
-rw-r--r--compiler/rustc_lint/src/unit_bindings.rs2
-rw-r--r--compiler/rustc_metadata/src/creader.rs27
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs13
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs1
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs22
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/cfg.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/coverageinfo.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs2
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs7
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs10
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs34
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs1
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs21
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs3
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs22
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs57
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs20
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/code_stats.rs18
-rw-r--r--compiler/rustc_session/src/parse.rs7
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs8
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs98
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs26
-rw-r--r--compiler/rustc_target/src/asm/arm.rs6
-rw-r--r--compiler/rustc_target/src/asm/avr.rs6
-rw-r--r--compiler/rustc_target/src/asm/bpf.rs6
-rw-r--r--compiler/rustc_target/src/asm/csky.rs6
-rw-r--r--compiler/rustc_target/src/asm/hexagon.rs6
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs6
-rw-r--r--compiler/rustc_target/src/asm/m68k.rs6
-rw-r--r--compiler/rustc_target/src/asm/mips.rs6
-rw-r--r--compiler/rustc_target/src/asm/mod.rs20
-rw-r--r--compiler/rustc_target/src/asm/msp430.rs6
-rw-r--r--compiler/rustc_target/src/asm/nvptx.rs6
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs6
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs6
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs6
-rw-r--r--compiler/rustc_target/src/asm/spirv.rs6
-rw-r--r--compiler/rustc_target/src/asm/wasm.rs6
-rw-r--r--compiler/rustc_target/src/asm/x86.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs10
-rw-r--r--compiler/stable_mir/src/mir/alloc.rs4
-rw-r--r--compiler/stable_mir/src/mir/body.rs10
-rw-r--r--compiler/stable_mir/src/target.rs2
-rw-r--r--library/core/src/char/convert.rs2
-rw-r--r--library/core/src/hint.rs5
-rw-r--r--library/core/src/intrinsics.rs244
-rw-r--r--library/core/src/intrinsics/simd.rs2
-rw-r--r--library/core/src/lib.rs4
-rw-r--r--library/core/src/mem/mod.rs60
-rw-r--r--library/core/src/num/nonzero.rs5
-rw-r--r--library/core/src/ops/index_range.rs5
-rw-r--r--library/core/src/panic/panic_info.rs5
-rw-r--r--library/core/src/panicking.rs4
-rw-r--r--library/core/src/pin.rs14
-rw-r--r--library/core/src/ptr/alignment.rs4
-rw-r--r--library/core/src/ptr/const_ptr.rs2
-rw-r--r--library/core/src/ptr/mod.rs54
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/core/src/slice/index.rs2
-rw-r--r--library/core/src/slice/mod.rs10
-rw-r--r--library/core/src/slice/raw.rs16
-rw-r--r--library/core/src/str/traits.rs2
-rw-r--r--library/core/src/ub_checks.rs158
-rw-r--r--library/portable-simd/.github/workflows/ci.yml5
-rw-r--r--library/portable-simd/Cargo.lock3
-rw-r--r--library/portable-simd/crates/core_simd/src/lib.rs12
-rw-r--r--library/portable-simd/crates/core_simd/src/masks.rs6
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle_dyn.rs8
-rw-r--r--library/portable-simd/crates/core_simd/src/vector.rs244
-rw-r--r--library/portable-simd/crates/core_simd/src/vendor.rs2
-rw-r--r--library/portable-simd/crates/core_simd/src/vendor/arm.rs8
-rw-r--r--library/portable-simd/crates/core_simd/tests/masked_load_store.rs35
-rw-r--r--library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs2
-rw-r--r--library/portable-simd/crates/std_float/Cargo.toml7
-rw-r--r--library/portable-simd/crates/std_float/src/lib.rs151
-rw-r--r--library/portable-simd/crates/std_float/tests/float.rs74
-rw-r--r--library/std/src/panicking.rs8
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sync/rwlock.rs2
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs83
-rw-r--r--library/std/src/sys/pal/uefi/os.rs8
-rw-r--r--library/unwind/src/lib.rs1
-rw-r--r--library/unwind/src/wasm.rs5
-rw-r--r--src/librustdoc/doctest.rs213
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/markdown.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs24
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/miri/.github/workflows/ci.yml2
-rw-r--r--src/tools/miri/bench-cargo-miri/range-iteration/Cargo.lock (renamed from src/tools/miri/bench-cargo-miri/invalidate/Cargo.lock)2
-rw-r--r--src/tools/miri/bench-cargo-miri/range-iteration/Cargo.toml (renamed from src/tools/miri/bench-cargo-miri/invalidate/Cargo.toml)2
-rw-r--r--src/tools/miri/bench-cargo-miri/range-iteration/src/main.rs (renamed from src/tools/miri/bench-cargo-miri/invalidate/src/main.rs)3
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs20
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs17
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs13
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs141
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs62
-rw-r--r--src/tools/miri/src/diagnostics.rs8
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/src/machine.rs21
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs48
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/event.rs4
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs13
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs6
-rw-r--r--src/tools/miri/test-cargo-miri/src/lib.rs18
-rw-r--r--src/tools/miri/test-cargo-miri/test.default.stdout.ref6
-rw-r--r--src/tools/miri/test-cargo-miri/test.filter.stdout.ref2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr7
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs19
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr20
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs19
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr20
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr7
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr7
-rw-r--r--src/tools/miri/tests/pass/intptrcast.rs26
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs25
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse2.rs5
-rw-r--r--src/tools/miri/tests/pass/main_fn.rs5
-rw-r--r--src/tools/miri/tests/pass/portable-simd.rs18
-rw-r--r--src/tools/run-make-support/src/lib.rs41
-rw-r--r--src/tools/rustfmt/src/parse/session.rs3
-rw-r--r--tests/assembly/x86_64-typed-swap.rs53
-rw-r--r--tests/codegen/intrinsics/typed_swap.rs78
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs16
-rw-r--r--tests/codegen/swap-small-types.rs5
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs1
-rw-r--r--tests/mir-opt/funky_arms.rs1
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.rs1
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.rs3
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff6
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff6
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/inline_coroutine_body.rs28
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff281
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff341
-rw-r--r--tests/mir-opt/pre-codegen/duplicate_switch_targets.rs1
-rw-r--r--tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/pre-codegen/mem_replace.rs2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.rs1
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.rs1
-rw-r--r--tests/run-make/rustdoc-test-args/foo.rs3
-rw-r--r--tests/run-make/rustdoc-test-args/rmake.rs18
-rw-r--r--tests/ui/asm/aarch64/type-check-3.stderr40
-rw-r--r--tests/ui/asm/bad-template.aarch64.stderr4
-rw-r--r--tests/ui/asm/bad-template.x86_64.stderr4
-rw-r--r--tests/ui/asm/x86_64/type-check-3.stderr16
-rw-r--r--tests/ui/associated-type-bounds/auxiliary/implied-predicates.rs7
-rw-r--r--tests/ui/associated-type-bounds/implied-predicates.rs9
-rw-r--r--tests/ui/associated-type-bounds/resolution-failure-building-vtable-representation-ice-90691.rs42
-rw-r--r--tests/ui/async-await/future-sizes/async-awaiting-fut.stdout14
-rw-r--r--tests/ui/async-await/future-sizes/large-arg.stdout6
-rw-r--r--tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs26
-rw-r--r--tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr42
-rw-r--r--tests/ui/const-generics/generic_const_exprs/failed-to-normalize-ice-issue-88421.rs36
-rw-r--r--tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs57
-rw-r--r--tests/ui/consts/ice-bad-input-type-for-cast-83056.rs7
-rw-r--r--tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr20
-rw-r--r--tests/ui/consts/missing_span_in_backtrace.stderr2
-rw-r--r--tests/ui/drop/norm-ice-106444.rs16
-rw-r--r--tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.rs16
-rw-r--r--tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr22
-rw-r--r--tests/ui/extern/extern-C-str-arg-ice-80125.rs15
-rw-r--r--tests/ui/extern/extern-C-str-arg-ice-80125.stderr35
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.rs17
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.stderr27
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs17
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr71
-rw-r--r--tests/ui/impl-trait/recursive-ice-101862.rs12
-rw-r--r--tests/ui/impl-trait/recursive-ice-101862.stderr24
-rw-r--r--tests/ui/inference/str-as-char.stderr12
-rw-r--r--tests/ui/issues/issue-23589.stderr4
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-2.stderr4
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-3.stderr8
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-5.stderr8
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-6.stderr12
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed6
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-1.rs6
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr20
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed4
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-2.rs4
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr13
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rs7
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr14
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr14
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr14
-rw-r--r--tests/ui/nll/ice-106874.rs48
-rw-r--r--tests/ui/nll/ice-106874.stderr90
-rw-r--r--tests/ui/panics/panic-in-message-fmt.rs25
-rw-r--r--tests/ui/panics/panic-in-message-fmt.run.stderr2
-rw-r--r--tests/ui/parser/issues/issue-64732.rs2
-rw-r--r--tests/ui/parser/issues/issue-64732.stderr6
-rw-r--r--tests/ui/parser/unicode-character-literal.fixed4
-rw-r--r--tests/ui/parser/unicode-character-literal.rs4
-rw-r--r--tests/ui/parser/unicode-character-literal.stderr8
-rw-r--r--tests/ui/polymorphization/ice-poly-with-mir-opts-90192.rs20
-rw-r--r--tests/ui/print_type_sizes/async.stdout2
-rw-r--r--tests/ui/privacy/decl-macro-infinite-global-import-cycle-ice-64784.rs16
-rw-r--r--tests/ui/privacy/pub-priv-dep/auxiliary/bar.rs6
-rw-r--r--tests/ui/privacy/pub-priv-dep/auxiliary/foo.rs2
-rw-r--r--tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs12
-rw-r--r--tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs15
-rw-r--r--tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr31
-rw-r--r--tests/ui/sanitizer/cfi-self-ref.rs33
-rw-r--r--tests/ui/sanitizer/cfi-virtual-auto.rs22
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr25
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr25
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.rs18
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.stderr25
-rw-r--r--tests/ui/specialization/broken-mir-drop-glue-107228.rs28
-rw-r--r--tests/ui/str/str-as-char.stderr4
-rw-r--r--tests/ui/traits/next-solver/dont-canonicalize-re-error.rs28
-rw-r--r--tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr21
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs15
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr33
-rw-r--r--tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs36
-rw-r--r--tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr25
-rw-r--r--tests/ui/type-alias-impl-trait/tait-param-inference-issue-117310.rs28
-rw-r--r--tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs21
-rw-r--r--tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr23
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs33
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr174
365 files changed, 4880 insertions, 1313 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index c182f3245e5..d7a31c8e80f 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -42,7 +42,7 @@ jobs:
 
           # Exit with error if open and S-waiting-on-bors
           if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then
-            exit 1
+            gh run cancel ${{ github.run_id }}
           fi
 
   update:
@@ -65,7 +65,10 @@ jobs:
 
       - name: cargo update
         # Remove first line that always just says "Updating crates.io index"
-        run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+        # If there are no changes, cancel the job here
+        run: |
+          cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+          git status --porcelain | grep -q Cargo.lock || gh run cancel ${{ github.run_id }}
       - name: upload Cargo.lock artifact for use in PR
         uses: actions/upload-artifact@v3
         with:
@@ -131,7 +134,7 @@ jobs:
           # Exit with error if PR is closed
           STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state')
           if [[ "$STATE" != "OPEN" ]]; then
-            exit 1
+            gh run cancel ${{ github.run_id }}
           fi
 
           gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 11a66fe87c9..eef6e8280af 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -81,7 +81,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         (self.arena.alloc_from_iter(stmts), expr)
     }
 
-    fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
+    fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
         let ty = l
             .ty
             .as_ref()
@@ -97,7 +97,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let span = self.lower_span(l.span);
         let source = hir::LocalSource::Normal;
         self.lower_attrs(hir_id, &l.attrs);
-        self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source })
+        self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
     }
 
     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 9078b1f889c..a1164008d0d 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -302,8 +302,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
-    fn visit_local(&mut self, l: &'hir Local<'hir>) {
-        self.insert(l.span, l.hir_id, Node::Local(l));
+    fn visit_local(&mut self, l: &'hir LetStmt<'hir>) {
+        self.insert(l.span, l.hir_id, Node::LetStmt(l));
         self.with_parent(l.hir_id, |this| {
             intravisit::walk_local(this, l);
         })
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d2744e8ff68..b5b98659e2f 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2341,7 +2341,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             debug_assert!(!a.is_empty());
             self.attrs.insert(hir_id.local_id, a);
         }
-        let local = hir::Local {
+        let local = hir::LetStmt {
             hir_id,
             init,
             pat,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index aa98d060f5f..35bd7d37992 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -622,7 +622,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
                     // FIXME: We make sure that this is a normal top-level binding,
                     // but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern
-                    if let hir::StmtKind::Let(hir::Local { span, ty, init: None, pat, .. }) =
+                    if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
                         &ex.kind
                         && let hir::PatKind::Binding(..) = pat.kind
                         && span.contains(self.decl_span)
@@ -800,7 +800,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
             let e = match node {
                 hir::Node::Expr(e) => e,
-                hir::Node::Local(hir::Local { els: Some(els), .. }) => {
+                hir::Node::LetStmt(hir::LetStmt { els: Some(els), .. }) => {
                     let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] };
                     finder.visit_block(els);
                     if !finder.found_breaks.is_empty() {
@@ -2124,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 hir::intravisit::walk_expr(self, e);
             }
 
-            fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
+            fn visit_local(&mut self, local: &'hir hir::LetStmt<'hir>) {
                 if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } =
                     local.pat
                     && let Some(init) = local.init
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 11561539f6d..0106e285604 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -4,7 +4,6 @@ use crate::session_diagnostics::{
     CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
     CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
 };
-use itertools::Itertools;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, Namespace};
@@ -226,16 +225,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         }
                     } else {
                         if autoderef_index.is_none() {
-                            autoderef_index =
-                                match place.projection.into_iter().rev().find_position(|elem| {
-                                    !matches!(
-                                        elem,
-                                        ProjectionElem::Deref | ProjectionElem::Downcast(..)
-                                    )
-                                }) {
-                                    Some((index, _)) => Some(place.projection.len() - index),
-                                    None => Some(0),
-                                };
+                            autoderef_index = match place.projection.iter().rposition(|elem| {
+                                !matches!(
+                                    elem,
+                                    ProjectionElem::Deref | ProjectionElem::Downcast(..)
+                                )
+                            }) {
+                                Some(index) => Some(index + 1),
+                                None => Some(0),
+                            };
                         }
                         if index >= autoderef_index.unwrap() {
                             buf.insert(0, '*');
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 36c2723b66d..2aeea1dd341 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -558,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     hir::intravisit::walk_stmt(self, stmt);
                     let expr = match stmt.kind {
                         hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
-                        hir::StmtKind::Let(hir::Local { init: Some(expr), .. }) => expr,
+                        hir::StmtKind::Let(hir::LetStmt { init: Some(expr), .. }) => expr,
                         _ => {
                             return;
                         }
@@ -737,7 +737,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             && let body = self.infcx.tcx.hir().body(body_id)
             && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value()
             && let node = self.infcx.tcx.hir_node(hir_id)
-            && let hir::Node::Local(hir::Local {
+            && let hir::Node::LetStmt(hir::LetStmt {
                 pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
                 ..
             })
@@ -1170,7 +1170,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 };
 
                 if let Some(hir_id) = hir_id
-                    && let hir::Node::Local(local) = self.infcx.tcx.hir_node(hir_id)
+                    && let hir::Node::LetStmt(local) = self.infcx.tcx.hir_node(hir_id)
                 {
                     let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
                     if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 700b5e13dec..a206aac0467 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2000,7 +2000,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     ConstraintCategory::SizedBound,
                 );
             }
-            &Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {}
+            &Rvalue::NullaryOp(NullOp::UbChecks, _) => {}
 
             Rvalue::ShallowInitBox(operand, ty) => {
                 self.check_operand(operand, location);
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 047dc56a32e..dbce6d165d2 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -780,7 +780,7 @@ fn codegen_stmt<'tcx>(
                         NullOp::OffsetOf(fields) => {
                             layout.offset_of_subfield(fx, fields.iter()).bytes()
                         }
-                        NullOp::UbCheck(_) => {
+                        NullOp::UbChecks => {
                             let val = fx.tcx.sess.opts.debug_assertions;
                             let val = CValue::by_val(
                                 fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 9b679019e96..06b14a1f118 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -541,7 +541,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
             let builtin_unreachable: RValue<'gcc> = unsafe {
                 std::mem::transmute(builtin_unreachable)
             };
-            self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
+            self.call(self.type_void(), None, None, builtin_unreachable, &[], None, None);
         }
 
         // Write results to outputs.
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index f5cda81f6ab..43cc46cfe68 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -25,7 +25,7 @@ use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers,
     TyAndLayout,
 };
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Instance};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_target::abi::{
@@ -592,12 +592,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         then: Block<'gcc>,
         catch: Block<'gcc>,
         _funclet: Option<&Funclet>,
+        instance: Option<Instance<'tcx>>,
     ) -> RValue<'gcc> {
         let try_block = self.current_func().new_block("try");
 
         let current_block = self.block.clone();
         self.block = try_block;
-        let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here?
+        let call = self.call(typ, fn_attrs, None, func, args, None, instance); // TODO(antoyo): use funclet here?
         self.block = current_block;
 
         let return_value =
@@ -1667,6 +1668,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         func: RValue<'gcc>,
         args: &[RValue<'gcc>],
         funclet: Option<&Funclet>,
+        _instance: Option<Instance<'tcx>>,
     ) -> RValue<'gcc> {
         // FIXME(antoyo): remove when having a proper API.
         let gcc_func = unsafe { std::mem::transmute(func) };
diff --git a/compiler/rustc_codegen_gcc/src/coverageinfo.rs b/compiler/rustc_codegen_gcc/src/coverageinfo.rs
index 849e9886ef3..4e44f78f23c 100644
--- a/compiler/rustc_codegen_gcc/src/coverageinfo.rs
+++ b/compiler/rustc_codegen_gcc/src/coverageinfo.rs
@@ -1,11 +1,11 @@
 use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods;
-use rustc_middle::mir::Coverage;
+use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
 
 use crate::builder::Builder;
 
 impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
-    fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) {
+    fn add_coverage(&mut self, _instance: Instance<'tcx>, _kind: &CoverageKind) {
         // TODO(antoyo)
     }
 }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index a6c8b72e851..cebd45c09aa 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -133,6 +133,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     func,
                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                     None,
+                    None,
                 )
             }
             sym::likely => self.expect(args[0].immediate(), true),
@@ -401,7 +402,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
     fn abort(&mut self) {
         let func = self.context.get_builtin_function("abort");
         let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
-        self.call(self.type_void(), None, None, func, &[], None);
+        self.call(self.type_void(), None, None, func, &[], None, None);
     }
 
     fn assume(&mut self, value: Self::Value) {
@@ -1103,7 +1104,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(
     dest: RValue<'gcc>,
 ) {
     if bx.sess().panic_strategy() == PanicStrategy::Abort {
-        bx.call(bx.type_void(), None, None, try_func, &[data], None);
+        bx.call(bx.type_void(), None, None, try_func, &[data], None, None);
         // Return 0 unconditionally from the intrinsic call;
         // we can never unwind.
         let ret_align = bx.tcx.data_layout.i32_align.abi;
@@ -1177,21 +1178,21 @@ fn codegen_gnu_try<'gcc>(
         let zero = bx.cx.context.new_rvalue_zero(bx.int_type);
         let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
         let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
-        bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
+        bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None);
         bx.ret(bx.const_i32(1));
 
         // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not
         // generate a try/catch.
         // FIXME(antoyo): add a check in the libgccjit API to prevent this.
         bx.switch_to_block(current_block);
-        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
+        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
     });
 
     let func = unsafe { std::mem::transmute(func) };
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None);
+    let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 74539d4d495..500904ce188 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -466,11 +466,11 @@ pub(crate) fn inline_asm_call<'ll>(
 
             let call = if !labels.is_empty() {
                 assert!(catch_funclet.is_none());
-                bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None)
+                bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
             } else if let Some((catch, funclet)) = catch_funclet {
-                bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet)
+                bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
             } else {
-                bx.call(fty, None, None, v, inputs, None)
+                bx.call(fty, None, None, v, inputs, None, None)
             };
 
             // Store mark in a metadata node so we can map LLVM errors
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 63e59ea13fc..a5a5ae73d77 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -19,9 +19,12 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_span::Span;
-use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
+use rustc_symbol_mangling::typeid::{
+    kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
+    TypeIdOptions,
+};
 use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
 use smallvec::SmallVec;
@@ -221,6 +224,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         then: &'ll BasicBlock,
         catch: &'ll BasicBlock,
         funclet: Option<&Funclet<'ll>>,
+        instance: Option<Instance<'tcx>>,
     ) -> &'ll Value {
         debug!("invoke {:?} with args ({:?})", llfn, args);
 
@@ -233,10 +237,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
 
         // Emit CFI pointer type membership test
-        self.cfi_type_test(fn_attrs, fn_abi, llfn);
+        self.cfi_type_test(fn_attrs, fn_abi, instance, llfn);
 
         // Emit KCFI operand bundle
-        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
+        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
         let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
         if let Some(kcfi_bundle) = kcfi_bundle {
             bundles.push(kcfi_bundle);
@@ -1231,6 +1235,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         llfn: &'ll Value,
         args: &[&'ll Value],
         funclet: Option<&Funclet<'ll>>,
+        instance: Option<Instance<'tcx>>,
     ) -> &'ll Value {
         debug!("call {:?} with args ({:?})", llfn, args);
 
@@ -1243,10 +1248,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
 
         // Emit CFI pointer type membership test
-        self.cfi_type_test(fn_attrs, fn_abi, llfn);
+        self.cfi_type_test(fn_attrs, fn_abi, instance, llfn);
 
         // Emit KCFI operand bundle
-        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
+        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
         let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
         if let Some(kcfi_bundle) = kcfi_bundle {
             bundles.push(kcfi_bundle);
@@ -1468,7 +1473,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
     pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
         let (ty, f) = self.cx.get_intrinsic(intrinsic);
-        self.call(ty, None, None, f, args, None)
+        self.call(ty, None, None, f, args, None, None)
     }
 
     fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
@@ -1526,7 +1531,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             format!("llvm.{instr}.sat.i{int_width}.f{float_width}")
         };
         let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
-        self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None)
+        self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None)
     }
 
     pub(crate) fn landing_pad(
@@ -1554,6 +1559,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         default_dest: &'ll BasicBlock,
         indirect_dest: &[&'ll BasicBlock],
         funclet: Option<&Funclet<'ll>>,
+        instance: Option<Instance<'tcx>>,
     ) -> &'ll Value {
         debug!("invoke {:?} with args ({:?})", llfn, args);
 
@@ -1566,10 +1572,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         }
 
         // Emit CFI pointer type membership test
-        self.cfi_type_test(fn_attrs, fn_abi, llfn);
+        self.cfi_type_test(fn_attrs, fn_abi, instance, llfn);
 
         // Emit KCFI operand bundle
-        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
+        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
         let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
         if let Some(kcfi_bundle) = kcfi_bundle {
             bundles.push(kcfi_bundle);
@@ -1601,6 +1607,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         &mut self,
         fn_attrs: Option<&CodegenFnAttrs>,
         fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+        instance: Option<Instance<'tcx>>,
         llfn: &'ll Value,
     ) {
         let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
@@ -1622,7 +1629,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
             }
 
-            let typeid = typeid_for_fnabi(self.tcx, fn_abi, options);
+            let typeid = if let Some(instance) = instance {
+                typeid_for_instance(self.tcx, &instance, options)
+            } else {
+                typeid_for_fnabi(self.tcx, fn_abi, options)
+            };
             let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
 
             // Test whether the function pointer is associated with the type identifier.
@@ -1644,6 +1655,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         &mut self,
         fn_attrs: Option<&CodegenFnAttrs>,
         fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+        instance: Option<Instance<'tcx>>,
         llfn: &'ll Value,
     ) -> Option<llvm::OperandBundleDef<'ll>> {
         let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
@@ -1665,7 +1677,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
             }
 
-            let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
+            let kcfi_typeid = if let Some(instance) = instance {
+                kcfi_typeid_for_instance(self.tcx, &instance, options)
+            } else {
+                kcfi_typeid_for_fnabi(self.tcx, fn_abi, options)
+            };
+
             Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
         } else {
             None
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 54f4bc06340..85277db6d53 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -14,7 +14,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_llvm::RustString;
 use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
-use rustc_middle::mir::Coverage;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::Instance;
 
@@ -75,7 +74,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
 impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
     #[instrument(level = "debug", skip(self))]
-    fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) {
+    fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
         // Our caller should have already taken care of inlining subtleties,
         // so we can assume that counter/expression IDs in this coverage
         // statement are meaningful for the given instance.
@@ -98,7 +97,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
             .entry(instance)
             .or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
 
-        let Coverage { kind } = coverage;
         match *kind {
             CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
                 "marker statement {kind:?} should have been removed by CleanupPostBorrowck"
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 2409b2e78d7..ab135e3ed64 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -181,6 +181,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     simple_fn,
                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                     None,
+                    Some(instance),
                 )
             }
             sym::likely => {
@@ -539,7 +540,7 @@ fn catch_unwind_intrinsic<'ll>(
 ) {
     if bx.sess().panic_strategy() == PanicStrategy::Abort {
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
-        bx.call(try_func_ty, None, None, try_func, &[data], None);
+        bx.call(try_func_ty, None, None, try_func, &[data], None, None);
         // Return 0 unconditionally from the intrinsic call;
         // we can never unwind.
         let ret_align = bx.tcx().data_layout.i32_align.abi;
@@ -640,7 +641,7 @@ fn codegen_msvc_try<'ll>(
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
         let slot = bx.alloca(bx.type_ptr(), ptr_align);
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
-        bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
+        bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None);
 
         bx.switch_to_block(normal);
         bx.ret(bx.const_i32(0));
@@ -684,7 +685,7 @@ fn codegen_msvc_try<'ll>(
         let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
         let ptr = bx.load(bx.type_ptr(), slot, ptr_align);
         let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
-        bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
+        bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
         bx.catch_ret(&funclet, caught);
 
         // The flag value of 64 indicates a "catch-all".
@@ -692,7 +693,7 @@ fn codegen_msvc_try<'ll>(
         let flags = bx.const_i32(64);
         let null = bx.const_null(bx.type_ptr());
         let funclet = bx.catch_pad(cs, &[null, flags, null]);
-        bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet));
+        bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet), None);
         bx.catch_ret(&funclet, caught);
 
         bx.switch_to_block(caught);
@@ -701,7 +702,7 @@ fn codegen_msvc_try<'ll>(
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
+    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
@@ -750,7 +751,7 @@ fn codegen_wasm_try<'ll>(
         //   }
         //
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
-        bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
+        bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None);
 
         bx.switch_to_block(normal);
         bx.ret(bx.const_i32(0));
@@ -766,7 +767,7 @@ fn codegen_wasm_try<'ll>(
         let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]);
 
         let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
-        bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
+        bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
         bx.catch_ret(&funclet, caught);
 
         bx.switch_to_block(caught);
@@ -775,7 +776,7 @@ fn codegen_wasm_try<'ll>(
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
+    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
@@ -818,7 +819,7 @@ fn codegen_gnu_try<'ll>(
         let data = llvm::get_param(bx.llfn(), 1);
         let catch_func = llvm::get_param(bx.llfn(), 2);
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
-        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
+        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
 
         bx.switch_to_block(then);
         bx.ret(bx.const_i32(0));
@@ -836,13 +837,13 @@ fn codegen_gnu_try<'ll>(
         bx.add_clause(vals, tydesc);
         let ptr = bx.extract_value(vals, 0);
         let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
-        bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
+        bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None);
         bx.ret(bx.const_i32(1));
     });
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
+    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
@@ -882,7 +883,7 @@ fn codegen_emcc_try<'ll>(
         let data = llvm::get_param(bx.llfn(), 1);
         let catch_func = llvm::get_param(bx.llfn(), 2);
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
-        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
+        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
 
         bx.switch_to_block(then);
         bx.ret(bx.const_i32(0));
@@ -920,13 +921,13 @@ fn codegen_emcc_try<'ll>(
         bx.store(is_rust_panic, catch_data_1, i8_align);
 
         let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
-        bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None);
+        bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None, None);
         bx.ret(bx.const_i32(1));
     });
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
+    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
@@ -1439,6 +1440,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             f,
             &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
             None,
+            None,
         );
         Ok(c)
     }
@@ -1607,6 +1609,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             f,
             &[args[1].immediate(), alignment, mask, args[0].immediate()],
             None,
+            None,
         );
         return Ok(v);
     }
@@ -1706,6 +1709,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             f,
             &[args[1].immediate(), alignment, mask, args[2].immediate()],
             None,
+            None,
         );
         return Ok(v);
     }
@@ -1799,6 +1803,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             f,
             &[args[2].immediate(), args[1].immediate(), alignment, mask],
             None,
+            None,
         );
         return Ok(v);
     }
@@ -1904,6 +1909,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             f,
             &[args[0].immediate(), args[1].immediate(), alignment, mask],
             None,
+            None,
         );
         return Ok(v);
     }
@@ -2352,11 +2358,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 f,
                 &[args[0].immediate(), bx.const_int(bx.type_i1(), 0)],
                 None,
+                None,
             ))
         } else {
             let fn_ty = bx.type_func(&[vec_ty], vec_ty);
             let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
-            Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None))
+            Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
         };
     }
 
@@ -2409,7 +2416,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 
         let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
         let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
-        let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None);
+        let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None, None);
         return Ok(v);
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 13809ef72ec..f7f2bfca838 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -462,27 +462,34 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let ptr_ty = cx.type_ptr();
         let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
 
-        let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type {
+        let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type
+        {
             let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
-            let start_fn = cx.get_fn_addr(ty::Instance::expect_resolve(
+            let start_instance = ty::Instance::expect_resolve(
                 cx.tcx(),
                 ty::ParamEnv::reveal_all(),
                 start_def_id,
                 cx.tcx().mk_args(&[main_ret_ty.into()]),
-            ));
+            );
+            let start_fn = cx.get_fn_addr(start_instance);
 
             let i8_ty = cx.type_i8();
             let arg_sigpipe = bx.const_u8(sigpipe);
 
             let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty);
-            (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe])
+            (
+                start_fn,
+                start_ty,
+                vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
+                Some(start_instance),
+            )
         } else {
             debug!("using user-defined start fn");
             let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
-            (rust_main, start_ty, vec![arg_argc, arg_argv])
+            (rust_main, start_ty, vec![arg_argc, arg_argv], None)
         };
 
-        let result = bx.call(start_ty, None, None, start_fn, &args, None);
+        let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
         if cx.sess().target.os.contains("uefi") {
             bx.ret(result);
         } else {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index dcc27a4f0e5..8c668597a43 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -232,6 +232,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
                 ret_llbb,
                 unwind_block,
                 self.funclet(fx),
+                instance,
             );
             if fx.mir[self.bb].is_cleanup {
                 bx.apply_attrs_to_cleanup_callsite(invokeret);
@@ -247,7 +248,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
             }
             MergingSucc::False
         } else {
-            let llret = bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx));
+            let llret =
+                bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance);
             if fx.mir[self.bb].is_cleanup {
                 bx.apply_attrs_to_cleanup_callsite(llret);
             }
@@ -502,7 +504,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let ty = location.ty(self.mir, bx.tcx()).ty;
         let ty = self.monomorphize(ty);
         let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
-        let instance = drop_fn.clone();
 
         if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
             // we don't actually need to drop anything.
@@ -518,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             args1 = [place.llval];
             &args1[..]
         };
-        let (drop_fn, fn_abi) =
+        let (drop_fn, fn_abi, drop_instance) =
             match ty.kind() {
                 // FIXME(eddyb) perhaps move some of this logic into
                 // `Instance::resolve_drop_in_place`?
@@ -550,6 +551,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
                             .get_fn(bx, vtable, ty, fn_abi),
                         fn_abi,
+                        virtual_drop,
                     )
                 }
                 ty::Dynamic(_, _, ty::DynStar) => {
@@ -592,9 +594,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
                             .get_fn(bx, meta.immediate(), ty, fn_abi),
                         fn_abi,
+                        virtual_drop,
                     )
                 }
-                _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
+                _ => (
+                    bx.get_fn_addr(drop_fn),
+                    bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
+                    drop_fn,
+                ),
             };
         helper.do_call(
             self,
@@ -605,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             Some((ReturnDest::Nothing, target)),
             unwind,
             &[],
-            Some(instance),
+            Some(drop_instance),
             mergeable_succ,
         )
     }
@@ -1699,7 +1706,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         } else {
             let fn_ty = bx.fn_decl_backend_type(fn_abi);
 
-            let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
+            let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None);
             bx.apply_attrs_to_cleanup_callsite(llret);
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
index ee70465966d..72187277228 100644
--- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
@@ -1,12 +1,12 @@
 use crate::traits::*;
 
-use rustc_middle::mir::Coverage;
+use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::SourceScope;
 
 use super::FunctionCx;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
-    pub fn codegen_coverage(&self, bx: &mut Bx, coverage: &Coverage, scope: SourceScope) {
+    pub fn codegen_coverage(&self, bx: &mut Bx, kind: &CoverageKind, scope: SourceScope) {
         // Determine the instance that coverage data was originally generated for.
         let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) {
             self.monomorphize(inlined)
@@ -15,6 +15,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         // Handle the coverage info in a backend-specific way.
-        bx.add_coverage(instance, coverage);
+        bx.add_coverage(instance, kind);
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 5532ff6e6a5..3e6cf0ece29 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -9,6 +9,7 @@ use crate::traits::*;
 use crate::MemFlags;
 
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
 use rustc_span::{sym, Span};
 use rustc_target::abi::{
     call::{FnAbi, PassMode},
@@ -75,6 +76,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let name = bx.tcx().item_name(def_id);
         let name_str = name.as_str();
 
+        // If we're swapping something that's *not* an `OperandValue::Ref`,
+        // then we can do it directly and avoid the alloca.
+        // Otherwise, we'll let the fallback MIR body take care of it.
+        if let sym::typed_swap = name {
+            let pointee_ty = fn_args.type_at(0);
+            let pointee_layout = bx.layout_of(pointee_ty);
+            if !bx.is_backend_ref(pointee_layout)
+                // But if we're not going to optimize, trying to use the fallback
+                // body just makes things worse, so don't bother.
+                || bx.sess().opts.optimize == OptLevel::No
+                // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
+                // reinterpretation of values as (chunkable) byte arrays, and the loop in the
+                // block optimization in `ptr::swap_nonoverlapping` is hard to rewrite back
+                // into the (unoptimized) direct swapping implementation, so we disable it.
+                || bx.sess().target.arch == "spirv"
+            {
+                let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout);
+                let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout);
+                bx.typed_place_swap(x_place, y_place);
+                return Ok(());
+            }
+        }
+
         let llret_ty = bx.backend_type(bx.layout_of(ret_ty));
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 15f2e0e56d8..0af84ff067a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -680,8 +680,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes();
                         bx.cx().const_usize(val)
                     }
-                    mir::NullOp::UbCheck(_) => {
-                        // In codegen, we want to check for language UB and library UB
+                    mir::NullOp::UbChecks => {
                         let val = bx.tcx().sess.opts.debug_assertions;
                         bx.cx().const_bool(val)
                     }
@@ -710,7 +709,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     } else {
                         None
                     };
-                    bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None)
+                    bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance))
                 } else {
                     bx.get_static(def_id)
                 };
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index ac7dfbb261d..2188eeae426 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -64,8 +64,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     cg_indirect_place.storage_dead(bx);
                 }
             }
-            mir::StatementKind::Coverage(box ref coverage) => {
-                self.codegen_coverage(bx, coverage, statement.source_info.scope);
+            mir::StatementKind::Coverage(ref kind) => {
+                self.codegen_coverage(bx, kind, statement.source_info.scope);
             }
             mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
                 if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) {
diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs
index e2e95cede60..c250cc26823 100644
--- a/compiler/rustc_codegen_ssa/src/size_of_val.rs
+++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs
@@ -70,7 +70,15 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             // (But we are in good company, this code is duplicated plenty of times.)
             let fn_ty = bx.fn_decl_backend_type(fn_abi);
 
-            bx.call(fn_ty, /* fn_attrs */ None, Some(fn_abi), llfn, &[msg.0, msg.1], None);
+            bx.call(
+                fn_ty,
+                /* fn_attrs */ None,
+                Some(fn_abi),
+                llfn,
+                &[msg.0, msg.1],
+                None,
+                None,
+            );
 
             // This function does not return so we can now return whatever we want.
             let size = bx.const_usize(layout.size.bytes());
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 36f37e3791b..6c8dcc5b690 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -1,22 +1,24 @@
 use super::abi::AbiBuilderMethods;
 use super::asm::AsmBuilderMethods;
+use super::consts::ConstMethods;
 use super::coverageinfo::CoverageInfoBuilderMethods;
 use super::debuginfo::DebugInfoBuilderMethods;
 use super::intrinsic::IntrinsicCallMethods;
 use super::misc::MiscMethods;
-use super::type_::{ArgAbiMethods, BaseTypeMethods};
+use super::type_::{ArgAbiMethods, BaseTypeMethods, LayoutTypeMethods};
 use super::{HasCodegen, StaticBuilderMethods};
 
 use crate::common::{
     AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
-use crate::mir::operand::OperandRef;
+use crate::mir::operand::{OperandRef, OperandValue};
 use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{Instance, Ty};
+use rustc_session::config::OptLevel;
 use rustc_span::Span;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
@@ -80,6 +82,7 @@ pub trait BuilderMethods<'a, 'tcx>:
         then: Self::BasicBlock,
         catch: Self::BasicBlock,
         funclet: Option<&Self::Funclet>,
+        instance: Option<Instance<'tcx>>,
     ) -> Self::Value;
     fn unreachable(&mut self);
 
@@ -267,6 +270,54 @@ pub trait BuilderMethods<'a, 'tcx>:
         flags: MemFlags,
     );
 
+    /// *Typed* copy for non-overlapping places.
+    ///
+    /// Has a default implementation in terms of `memcpy`, but specific backends
+    /// can override to do something smarter if possible.
+    ///
+    /// (For example, typed load-stores with alias metadata.)
+    fn typed_place_copy(
+        &mut self,
+        dst: PlaceRef<'tcx, Self::Value>,
+        src: PlaceRef<'tcx, Self::Value>,
+    ) {
+        debug_assert!(src.llextra.is_none());
+        debug_assert!(dst.llextra.is_none());
+        debug_assert_eq!(dst.layout.size, src.layout.size);
+        if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout) {
+            // If we're not optimizing, the aliasing information from `memcpy`
+            // isn't useful, so just load-store the value for smaller code.
+            let temp = self.load_operand(src);
+            temp.val.store(self, dst);
+        } else if !dst.layout.is_zst() {
+            let bytes = self.const_usize(dst.layout.size.bytes());
+            self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, MemFlags::empty());
+        }
+    }
+
+    /// *Typed* swap for non-overlapping places.
+    ///
+    /// Avoids `alloca`s for Immediates and ScalarPairs.
+    ///
+    /// FIXME: Maybe do something smarter for Ref types too?
+    /// For now, the `typed_swap` intrinsic just doesn't call this for those
+    /// cases (in non-debug), preferring the fallback body instead.
+    fn typed_place_swap(
+        &mut self,
+        left: PlaceRef<'tcx, Self::Value>,
+        right: PlaceRef<'tcx, Self::Value>,
+    ) {
+        let mut temp = self.load_operand(left);
+        if let OperandValue::Ref(..) = temp.val {
+            // The SSA value isn't stand-alone, so we need to copy it elsewhere
+            let alloca = PlaceRef::alloca(self, left.layout);
+            self.typed_place_copy(alloca, left);
+            temp = self.load_operand(alloca);
+        }
+        self.typed_place_copy(left, right);
+        temp.val.store(self, right);
+    }
+
     fn select(
         &mut self,
         cond: Self::Value,
@@ -339,6 +390,7 @@ pub trait BuilderMethods<'a, 'tcx>:
         llfn: Self::Value,
         args: &[Self::Value],
         funclet: Option<&Self::Funclet>,
+        instance: Option<Instance<'tcx>>,
     ) -> Self::Value;
     fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
index 7e8de0ddc5b..d1d813bd389 100644
--- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
@@ -1,5 +1,5 @@
 use super::BackendTypes;
-use rustc_middle::mir::Coverage;
+use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
 
 pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
@@ -7,5 +7,5 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
     ///
     /// This can potentially be a no-op in backends that don't support
     /// coverage instrumentation.
-    fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage);
+    fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind);
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 72cce43a3fa..555833759eb 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -120,6 +120,20 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
         immediate: bool,
     ) -> Self::Type;
 
+    /// A type that produces an [`OperandValue::Ref`] when loaded.
+    ///
+    /// AKA one that's not a ZST, not `is_backend_immediate`, and
+    /// not `is_backend_scalar_pair`. For such a type, a
+    /// [`load_operand`] doesn't actually `load` anything.
+    ///
+    /// [`OperandValue::Ref`]: crate::mir::operand::OperandValue::Ref
+    /// [`load_operand`]: super::BuilderMethods::load_operand
+    fn is_backend_ref(&self, layout: TyAndLayout<'tcx>) -> bool {
+        !(layout.is_zst()
+            || self.is_backend_immediate(layout)
+            || self.is_backend_scalar_pair(layout))
+    }
+
     /// A type that can be used in a [`super::BuilderMethods::load`] +
     /// [`super::BuilderMethods::store`] pair to implement a *typed* copy,
     /// such as a MIR `*_0 = *_1`.
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 16bd0296247..5a1c7cc4209 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -3,7 +3,7 @@ use either::{Left, Right};
 use rustc_hir::def::DefKind;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
 use rustc_middle::mir::{self, ConstAlloc, ConstValue};
-use rustc_middle::query::{Key, TyCtxtAt};
+use rustc_middle::query::TyCtxtAt;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -243,24 +243,6 @@ pub(crate) fn turn_into_const_value<'tcx>(
     op_to_const(&ecx, &mplace.into(), /* for diagnostics */ false)
 }
 
-/// Computes the tag (if any) for a given type and variant.
-#[instrument(skip(tcx), level = "debug")]
-pub fn tag_for_variant_provider<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (ty, variant_index): (Ty<'tcx>, abi::VariantIdx),
-) -> Option<ty::ScalarInt> {
-    assert!(ty.is_enum());
-
-    let ecx = InterpCx::new(
-        tcx,
-        ty.default_span(tcx),
-        ty::ParamEnv::reveal_all(),
-        crate::const_eval::DummyMachine,
-    );
-
-    ecx.tag_for_variant(ty, variant_index).unwrap().map(|(tag, _tag_field)| tag)
-}
-
 #[instrument(skip(tcx), level = "debug")]
 pub fn eval_to_const_value_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index b768c429070..8efc67bcb0c 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -2,10 +2,11 @@
 
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::InterpErrorInfo;
-use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::query::{Key, TyCtxtAt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::VariantIdx;
 
-use crate::interpret::format_interp_error;
+use crate::interpret::{format_interp_error, InterpCx};
 
 mod dummy_machine;
 mod error;
@@ -77,3 +78,21 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
 
     Some(mir::DestructuredConstant { variant, fields })
 }
+
+/// Computes the tag (if any) for a given type and variant.
+#[instrument(skip(tcx), level = "debug")]
+pub fn tag_for_variant_provider<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (ty, variant_index): (Ty<'tcx>, VariantIdx),
+) -> Option<ty::ScalarInt> {
+    assert!(ty.is_enum());
+
+    let ecx = InterpCx::new(
+        tcx,
+        ty.default_span(tcx),
+        ty::ParamEnv::reveal_all(),
+        crate::const_eval::DummyMachine,
+    );
+
+    ecx.tag_for_variant(ty, variant_index).unwrap().map(|(tag, _tag_field)| tag)
+}
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 40469c6632c..704f597cfdb 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             None => {
                 // No need to write the tag here, because an untagged variant is
-                // implicitly encoded. For `Niche`-optimized enums, it's by
+                // implicitly encoded. For `Niche`-optimized enums, this works by
                 // simply by having a value that is outside the niche variants.
                 // But what if the data stored here does not actually encode
                 // this variant? That would be bad! So let's double-check...
@@ -227,8 +227,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(ImmTy::from_scalar(discr_value, discr_layout))
     }
 
-    /// Computes the tag value and its field number (if any) of a given variant
-    /// of type `ty`.
+    /// Computes how to write the tag of a given variant of enum `ty`:
+    /// - `None` means that nothing needs to be done as the variant is encoded implicitly
+    /// - `Some((val, field_idx))` means that the given integer value needs to be stored at the
+    ///   given field index.
     pub(crate) fn tag_for_variant(
         &self,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index a84ef4ce08e..a8478f721c7 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -21,8 +21,8 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::Size;
 
 use super::{
-    util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, MPlaceTy, Machine, OpTy,
-    Pointer,
+    memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx,
+    MPlaceTy, Machine, OpTy, Pointer,
 };
 
 use crate::fluent_generated as fluent;
@@ -414,6 +414,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
             }
+            sym::typed_swap => {
+                self.typed_swap_intrinsic(&args[0], &args[1])?;
+            }
 
             sym::vtable_size => {
                 let ptr = self.read_pointer(&args[0])?;
@@ -607,6 +610,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.mem_copy(src, dst, size, nonoverlapping)
     }
 
+    /// Does a *typed* swap of `*left` and `*right`.
+    fn typed_swap_intrinsic(
+        &mut self,
+        left: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        right: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+    ) -> InterpResult<'tcx> {
+        let left = self.deref_pointer(left)?;
+        let right = self.deref_pointer(right)?;
+        debug_assert_eq!(left.layout, right.layout);
+        let kind = MemoryKind::Stack;
+        let temp = self.allocate(left.layout, kind)?;
+        self.copy_op(&left, &temp)?;
+        self.copy_op(&right, &left)?;
+        self.copy_op(&temp, &right)?;
+        self.deallocate_ptr(temp.ptr(), None, kind)?;
+        Ok(())
+    }
+
     pub(crate) fn write_bytes_intrinsic(
         &mut self,
         dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 54bac70da38..9114ffff6fd 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -258,17 +258,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let val = layout.offset_of_subfield(self, fields.iter()).bytes();
                         Scalar::from_target_usize(val, self)
                     }
-                    mir::NullOp::UbCheck(kind) => {
-                        // We want to enable checks for library UB, because the interpreter doesn't
-                        // know about those on its own.
-                        // But we want to disable checks for language UB, because the interpreter
-                        // has its own better checks for that.
-                        let should_check = match kind {
-                            mir::UbKind::LibraryUb => self.tcx.sess.opts.debug_assertions,
-                            mir::UbKind::LanguageUb => false,
-                        };
-                        Scalar::from_bool(should_check)
-                    }
+                    mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.opts.debug_assertions),
                 };
                 self.write_scalar(val, &dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index a93e8138aa4..da8e28d0298 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             Rvalue::Cast(_, _, _) => {}
 
             Rvalue::NullaryOp(
-                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbCheck(_),
+                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks,
                 _,
             ) => {}
             Rvalue::ShallowInitBox(_, _) => {}
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 4bc49f90607..08e3e42a82e 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -85,7 +85,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
         cfg_checker.check_cleanup_control_flow();
 
         // Also run the TypeChecker.
-        for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) {
+        for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body, body) {
             cfg_checker.fail(location, msg);
         }
 
@@ -346,8 +346,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
                     self.fail(location, format!("explicit `{kind:?}` is forbidden"));
                 }
             }
-            StatementKind::Coverage(coverage) => {
-                let kind = &coverage.kind;
+            StatementKind::Coverage(kind) => {
                 if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup)
                     && let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind
                 {
@@ -541,19 +540,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
 
 /// A faster version of the validation pass that only checks those things which may break when
 /// instantiating any generic parameters.
+///
+/// `caller_body` is used to detect cycles in MIR inlining and MIR validation before
+/// `optimized_mir` is available.
 pub fn validate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
     mir_phase: MirPhase,
     param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
+    caller_body: &Body<'tcx>,
 ) -> Vec<(Location, String)> {
-    let mut type_checker = TypeChecker { body, tcx, param_env, mir_phase, failures: Vec::new() };
+    let mut type_checker =
+        TypeChecker { body, caller_body, tcx, param_env, mir_phase, failures: Vec::new() };
     type_checker.visit_body(body);
     type_checker.failures
 }
 
 struct TypeChecker<'a, 'tcx> {
     body: &'a Body<'tcx>,
+    caller_body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     mir_phase: MirPhase,
@@ -705,8 +710,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                     &ty::Coroutine(def_id, args) => {
                         let f_ty = if let Some(var) = parent_ty.variant_index {
-                            let gen_body = if def_id == self.body.source.def_id() {
-                                self.body
+                            // If we're currently validating an inlined copy of this body,
+                            // then it will no longer be parameterized over the original
+                            // args of the coroutine. Otherwise, we prefer to use this body
+                            // since we may be in the process of computing this MIR in the
+                            // first place.
+                            let gen_body = if def_id == self.caller_body.source.def_id() {
+                                self.caller_body
                             } else {
                                 self.tcx.optimized_mir(def_id)
                             };
@@ -1168,7 +1178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             Rvalue::Repeat(_, _)
             | Rvalue::ThreadLocalRef(_)
             | Rvalue::AddressOf(_, _)
-            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbCheck(_), _)
+            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
             | Rvalue::Discriminant(_) => {}
         }
         self.super_rvalue(rvalue, location);
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index fceccb7e9b6..bd8e78bda26 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -541,6 +541,7 @@ pub struct SilentEmitter {
     pub fallback_bundle: LazyFallbackBundle,
     pub fatal_dcx: DiagCtxt,
     pub fatal_note: Option<String>,
+    pub emit_fatal_diagnostic: bool,
 }
 
 impl Translate for SilentEmitter {
@@ -561,7 +562,7 @@ impl Emitter for SilentEmitter {
     }
 
     fn emit_diagnostic(&mut self, mut diag: DiagInner) {
-        if diag.level == Level::Fatal {
+        if self.emit_fatal_diagnostic && diag.level == Level::Fatal {
             if let Some(fatal_note) = &self.fatal_note {
                 diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
             }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 238bc63ec58..7b40954e735 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -612,12 +612,18 @@ impl DiagCtxt {
         Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
     }
 
-    pub fn make_silent(&mut self, fallback_bundle: LazyFallbackBundle, fatal_note: Option<String>) {
+    pub fn make_silent(
+        &mut self,
+        fallback_bundle: LazyFallbackBundle,
+        fatal_note: Option<String>,
+        emit_fatal_diagnostic: bool,
+    ) {
         self.wrap_emitter(|old_dcx| {
             Box::new(emitter::SilentEmitter {
                 fallback_bundle,
                 fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) },
                 fatal_note,
+                emit_fatal_diagnostic,
             })
         });
     }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 162ec16fabc..cc0ab05d422 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1220,7 +1220,7 @@ pub struct Stmt<'hir> {
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub enum StmtKind<'hir> {
     /// A local (`let`) binding.
-    Let(&'hir Local<'hir>),
+    Let(&'hir LetStmt<'hir>),
 
     /// An item binding.
     Item(ItemId),
@@ -1234,7 +1234,7 @@ pub enum StmtKind<'hir> {
 
 /// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
-pub struct Local<'hir> {
+pub struct LetStmt<'hir> {
     pub pat: &'hir Pat<'hir>,
     /// Type annotation, if any (otherwise the type will be inferred).
     pub ty: Option<&'hir Ty<'hir>>,
@@ -1264,7 +1264,7 @@ pub struct Arm<'hir> {
     pub body: &'hir Expr<'hir>,
 }
 
-/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a [`Local`]), occurring in an `if-let`
+/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a [`LetStmt`]), occurring in an `if-let`
 /// or `let-else`, evaluating to a boolean. Typically the pattern is refutable.
 ///
 /// In an `if let`, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of
@@ -1861,7 +1861,7 @@ pub enum ExprKind<'hir> {
     DropTemps(&'hir Expr<'hir>),
     /// A `let $pat = $expr` expression.
     ///
-    /// These are not `Local` and only occur as expressions.
+    /// These are not [`LetStmt`] and only occur as expressions.
     /// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`.
     Let(&'hir LetExpr<'hir>),
     /// An `if` block, with an optional else block.
@@ -3529,7 +3529,7 @@ pub enum Node<'hir> {
     PatField(&'hir PatField<'hir>),
     Arm(&'hir Arm<'hir>),
     Block(&'hir Block<'hir>),
-    Local(&'hir Local<'hir>),
+    LetStmt(&'hir LetStmt<'hir>),
     /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants
     /// with synthesized constructors.
     Ctor(&'hir VariantData<'hir>),
@@ -3585,7 +3585,7 @@ impl<'hir> Node<'hir> {
             | Node::Ctor(..)
             | Node::Pat(..)
             | Node::Arm(..)
-            | Node::Local(..)
+            | Node::LetStmt(..)
             | Node::Crate(..)
             | Node::Ty(..)
             | Node::TraitRef(..)
@@ -3757,7 +3757,7 @@ impl<'hir> Node<'hir> {
         expect_pat_field,     &'hir PatField<'hir>,     Node::PatField(n),     n;
         expect_arm,           &'hir Arm<'hir>,          Node::Arm(n),          n;
         expect_block,         &'hir Block<'hir>,        Node::Block(n),        n;
-        expect_local,         &'hir Local<'hir>,        Node::Local(n),        n;
+        expect_let_stmt,      &'hir LetStmt<'hir>,      Node::LetStmt(n),      n;
         expect_ctor,          &'hir VariantData<'hir>,  Node::Ctor(n),         n;
         expect_lifetime,      &'hir Lifetime,           Node::Lifetime(n),     n;
         expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n;
@@ -3787,7 +3787,7 @@ mod size_asserts {
     static_assert_size!(ImplItemKind<'_>, 40);
     static_assert_size!(Item<'_>, 88);
     static_assert_size!(ItemKind<'_>, 56);
-    static_assert_size!(Local<'_>, 64);
+    static_assert_size!(LetStmt<'_>, 64);
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
     static_assert_size!(Path<'_>, 40);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 468c7fd5c73..8c44f21a57b 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -320,7 +320,7 @@ pub trait Visitor<'v>: Sized {
     fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result {
         walk_foreign_item(self, i)
     }
-    fn visit_local(&mut self, l: &'v Local<'v>) -> Self::Result {
+    fn visit_local(&mut self, l: &'v LetStmt<'v>) -> Self::Result {
         walk_local(self, l)
     }
     fn visit_block(&mut self, b: &'v Block<'v>) -> Self::Result {
@@ -606,7 +606,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
     V::Result::output()
 }
 
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) -> V::Result {
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -> V::Result {
     // Intentionally visiting the expr first - the initialization expr
     // dominates the local's definition.
     visit_opt!(visitor, visit_expr, local.init);
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 8fb6569aa14..50f88eb970a 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -639,10 +639,9 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         }
     }
 
-    if !unnormalized_trait_sig.output().references_error() {
-        debug_assert!(
-            !collector.types.is_empty(),
-            "expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
+    if !unnormalized_trait_sig.output().references_error() && collector.types.is_empty() {
+        tcx.dcx().delayed_bug(
+            "expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`",
         );
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 0b526a8c977..f482ae4f5fa 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -127,8 +127,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::variant_count
         | sym::is_val_statically_known
         | sym::ptr_mask
-        | sym::check_language_ub
-        | sym::check_library_ub
+        | sym::ub_checks
         | sym::fadd_algebraic
         | sym::fsub_algebraic
         | sym::fmul_algebraic
@@ -484,6 +483,8 @@ pub fn check_intrinsic_type(
                 (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
             }
 
+            sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], Ty::new_unit(tcx)),
+
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
                     tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
@@ -569,7 +570,7 @@ pub fn check_intrinsic_type(
                 (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
             }
 
-            sym::check_language_ub | sym::check_library_ub => (0, 1, Vec::new(), tcx.types.bool),
+            sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
 
             sym::simd_eq
             | sym::simd_ne
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 6cb15708a42..df4db3ec3fb 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -6,7 +6,9 @@ use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Symbol;
 use rustc_target::abi::FieldIdx;
-use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
+use rustc_target::asm::{
+    InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
+};
 
 pub struct InlineAsmCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -251,8 +253,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         }
 
         // Check whether a modifier is suggested for using this type.
-        if let Some((suggested_modifier, suggested_result)) =
-            reg_class.suggest_modifier(asm_arch, asm_ty)
+        if let Some(ModifierInfo {
+            modifier: suggested_modifier,
+            result: suggested_result,
+            size: suggested_size,
+        }) = reg_class.suggest_modifier(asm_arch, asm_ty)
         {
             // Search for any use of this operand without a modifier and emit
             // the suggestion for them.
@@ -266,8 +271,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                 }
             }
             if !spans.is_empty() {
-                let (default_modifier, default_result) =
-                    reg_class.default_modifier(asm_arch).unwrap();
+                let ModifierInfo {
+                    modifier: default_modifier,
+                    result: default_result,
+                    size: default_size,
+                } = reg_class.default_modifier(asm_arch).unwrap();
                 self.tcx.node_span_lint(
                     lint::builtin::ASM_SUB_REGISTER,
                     expr.hir_id,
@@ -276,10 +284,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     |lint| {
                         lint.span_label(expr.span, "for this argument");
                         lint.help(format!(
-                            "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
+                            "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)",
                         ));
                         lint.help(format!(
-                            "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
+                            "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)",
                         ));
                     },
                 );
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index e84bce92fc5..dcabac6d780 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
+use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt};
 use rustc_index::Idx;
 use rustc_middle::middle::region::*;
 use rustc_middle::ty::TyCtxt;
@@ -123,7 +123,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
 
         for (i, statement) in blk.stmts.iter().enumerate() {
             match statement.kind {
-                hir::StmtKind::Let(hir::Local { els: Some(els), .. }) => {
+                hir::StmtKind::Let(LetStmt { els: Some(els), .. }) => {
                     // Let-else has a special lexical structure for variables.
                     // First we take a checkpoint of the current scope context here.
                     let mut prev_cx = visitor.cx;
@@ -855,7 +855,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         resolve_expr(self, ex);
     }
-    fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
         resolve_local(self, Some(l.pat), l.init)
     }
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 71fdcc76a70..36f59b4ac2e 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -113,7 +113,7 @@ impl<'a> State<'a> {
             // `hir_map` to reconstruct their full structure for pretty
             // printing.
             Node::Ctor(..) => panic!("cannot print isolated Ctor"),
-            Node::Local(a) => self.print_local_decl(a),
+            Node::LetStmt(a) => self.print_local_decl(a),
             Node::Crate(..) => panic!("cannot print Crate"),
             Node::WhereBoundPredicate(pred) => {
                 self.print_formal_generic_params(pred.bound_generic_params);
@@ -1544,7 +1544,7 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
+    fn print_local_decl(&mut self, loc: &hir::LetStmt<'_>) {
         self.print_pat(loc.pat);
         if let Some(ty) = loc.ty {
             self.word_space(":");
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 1805e9fbb98..9b7db9e4c8e 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -408,7 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
         }
-        if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
+        if let hir::Node::LetStmt(hir::LetStmt { ty: Some(_), pat, .. }) = node {
             return Some((pat.span, "expected because of this assignment".to_string()));
         }
         None
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 67ff412651c..564de4ab9e7 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -299,8 +299,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return false;
         };
         let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
-            hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
-            hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
+            hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
+            hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => (init.hir_id, Some(*init)),
             _ => return false,
         };
         let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else {
@@ -678,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         error: Option<TypeError<'tcx>>,
     ) {
         match (self.tcx.parent_hir_node(expr.hir_id), error) {
-            (hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _)
+            (hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init: Some(init), .. }), _)
                 if init.hir_id == expr.hir_id =>
             {
                 // Point at `let` assignment type.
@@ -724,11 +724,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             primary_span = pat.span;
                             secondary_span = pat.span;
                             match self.tcx.parent_hir_node(pat.hir_id) {
-                                hir::Node::Local(hir::Local { ty: Some(ty), .. }) => {
+                                hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
                                     primary_span = ty.span;
                                     post_message = " type";
                                 }
-                                hir::Node::Local(hir::Local { init: Some(init), .. }) => {
+                                hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
                                     primary_span = init.span;
                                     post_message = " value";
                                 }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index f632e495295..f38f04fce43 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1451,7 +1451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         });
         let Some((
             _,
-            hir::Node::Local(hir::Local { ty: Some(ty), .. })
+            hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. })
             | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }),
         )) = parent_node
         else {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index f3d523efd68..3b6accb92ae 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -371,7 +371,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
     fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
         match stmt.kind {
-            hir::StmtKind::Let(hir::Local { pat, init: Some(expr), els, .. }) => {
+            hir::StmtKind::Let(hir::LetStmt { pat, init: Some(expr), els, .. }) => {
                 self.walk_local(expr, pat, *els, |_| {})
             }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 3a0a3de968d..ebc5e11a561 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1601,7 +1601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Type check a `let` statement.
-    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+    pub fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
         self.check_decl(local.into());
         if local.pat.is_never_pattern() {
             self.diverges.set(Diverges::Always {
@@ -1789,7 +1789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             [
                                                 hir::Stmt {
                                                     kind:
-                                                        hir::StmtKind::Let(hir::Local {
+                                                        hir::StmtKind::Let(hir::LetStmt {
                                                             source:
                                                                 hir::LocalSource::AssignDesugar(_),
                                                             ..
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 810735d5424..442bfd75746 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -317,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                             expr_id = parent_id;
                         }
-                        Node::Local(local) => {
+                        Node::LetStmt(local) => {
                             if let Some(mut ty) = local.ty {
                                 while let Some(index) = tuple_indexes.pop() {
                                     match ty.kind {
@@ -1348,7 +1348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         //                     ++++++++++
         // since the user probably just misunderstood how `let else`
         // and `&&` work together.
-        if let Some((_, hir::Node::Local(local))) = cond_parent
+        if let Some((_, hir::Node::LetStmt(local))) = cond_parent
             && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
                 &local.pat.kind
             && let hir::QPath::Resolved(None, path) = qpath
@@ -1748,7 +1748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 match self.tcx.parent_hir_node(*hir_id) {
                     // foo.clone()
-                    hir::Node::Local(hir::Local { init: Some(init), .. }) => {
+                    hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
                         self.note_type_is_not_clone_inner_expr(init)
                     }
                     // When `expr` is more complex like a tuple
@@ -1757,7 +1757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         kind: hir::PatKind::Tuple(pats, ..),
                         ..
                     }) => {
-                        let hir::Node::Local(hir::Local { init: Some(init), .. }) =
+                        let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
                             self.tcx.parent_hir_node(*pat_hir_id)
                         else {
                             return expr;
@@ -1791,7 +1791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } =
                         call_expr_path
                     && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
-                    && let hir::Node::Local(hir::Local { init: Some(init), .. }) =
+                    && let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
                         self.tcx.parent_hir_node(*hir_id)
                     && let Expr {
                         kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
@@ -3147,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
             return;
         };
-        let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
+        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
             self.tcx.parent_hir_node(pat.hir_id)
         else {
             return;
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 8fddccab5bf..1fa799dcec7 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -29,7 +29,7 @@ impl<'a> DeclOrigin<'a> {
     }
 }
 
-/// A declaration is an abstraction of [hir::Local] and [hir::LetExpr].
+/// A declaration is an abstraction of [hir::LetStmt] and [hir::LetExpr].
 ///
 /// It must have a hir_id, as this is how we connect gather_locals to the check functions.
 pub(super) struct Declaration<'a> {
@@ -41,9 +41,9 @@ pub(super) struct Declaration<'a> {
     pub origin: DeclOrigin<'a>,
 }
 
-impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
-    fn from(local: &'a hir::Local<'a>) -> Self {
-        let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
+impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> {
+    fn from(local: &'a hir::LetStmt<'a>) -> Self {
+        let hir::LetStmt { hir_id, pat, ty, span, init, els, source: _ } = *local;
         Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
     }
 }
@@ -120,7 +120,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
     // Add explicitly-declared locals.
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         self.declare(local.into());
         intravisit::walk_local(self, local)
     }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 62664f27662..0dcde0cdecb 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2163,7 +2163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         match (filename, parent_node) {
                             (
                                 FileName::Real(_),
-                                Node::Local(hir::Local {
+                                Node::LetStmt(hir::LetStmt {
                                     source: hir::LocalSource::Normal,
                                     ty,
                                     ..
@@ -2218,7 +2218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 impl<'v> Visitor<'v> for LetVisitor {
                     type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
                     fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
-                        if let hir::StmtKind::Let(&hir::Local { pat, init, .. }) = ex.kind
+                        if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
                             && let Binding(_, _, ident, ..) = pat.kind
                             && ident.name == self.ident_name
                         {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 5ddd0f8be25..7ecd380ebeb 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -744,7 +744,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let ident_kind = match binding_parent {
                     hir::Node::Param(_) => "parameter",
-                    hir::Node::Local(_) => "variable",
+                    hir::Node::LetStmt(_) => "variable",
                     hir::Node::Arm(_) => "binding",
 
                     // Provide diagnostics only if the parent pattern is struct-like,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index f88988ec8a3..e489b431e81 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -217,7 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 bug!();
             };
             for stmt in block.stmts {
-                let hir::StmtKind::Let(hir::Local {
+                let hir::StmtKind::Let(hir::LetStmt {
                     init: Some(init),
                     source: hir::LocalSource::AsyncFn,
                     pat,
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0740a3fd3e9..f4516b684c3 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -351,7 +351,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
         intravisit::walk_pat(self, p);
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         intravisit::walk_local(self, l);
         let var_ty = self.fcx.local_ty(l.span, l.hir_id);
         let var_ty = self.resolve(var_ty, &l.span);
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index e44a6ae3b3f..521c65c6009 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -169,7 +169,7 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position
 
 infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
 infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
-infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
+infer_meant_str_literal = if you meant to write a string literal, use double quotes
 infer_mismatched_static_lifetime = incompatible lifetime on type
 infer_more_targeted = {$has_param_name ->
     [true] `{$param_name}`
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index a3cf0d8e520..d0b1f2848ff 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1339,15 +1339,12 @@ pub enum TypeErrorAdditionalDiags {
         span: Span,
         code: String,
     },
-    #[suggestion(
-        infer_meant_str_literal,
-        code = "\"{code}\"",
-        applicability = "machine-applicable"
-    )]
+    #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")]
     MeantStrLiteral {
-        #[primary_span]
-        span: Span,
-        code: String,
+        #[suggestion_part(code = "\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
     },
     #[suggestion(
         infer_consider_specifying_length,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 7ce6c35f8c3..82634f7308d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2079,16 +2079,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 // If a string was expected and the found expression is a character literal,
                 // perhaps the user meant to write `"s"` to specify a string literal.
                 (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
-                    if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
-                        if let Some(code) =
-                            code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
-                        {
-                            suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
-                                span,
-                                code: escape_literal(code),
-                            })
-                        }
-                    }
+                    suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
+                        start: span.with_hi(span.lo() + BytePos(1)),
+                        end: span.with_lo(span.hi() - BytePos(1)),
+                    })
                 }
                 // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
                 // we try to suggest to add the missing `let` for `if let Some(..) = expr`
@@ -2140,7 +2134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         // the same span as the error and the type is specified.
                         if let hir::Stmt {
                             kind:
-                                hir::StmtKind::Let(hir::Local {
+                                hir::StmtKind::Let(hir::LetStmt {
                                     init: Some(hir::Expr { span: init_span, .. }),
                                     ty: Some(array_ty),
                                     ..
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index ce9001ccb1c..f89ed256a08 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -11,7 +11,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
+use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::{
     ConstVariableOrigin, ConstVariableOriginKind, ConstVariableValue,
@@ -1122,7 +1122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
         self.tecx.tcx.hir()
     }
 
-    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
         intravisit::walk_local(self, local);
 
         if let Some(ty) = self.opt_node_type(local.hir_id) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 9081fbaa2dc..e220c4d02a2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -2,7 +2,7 @@ use crate::infer::error_reporting::hir::Path;
 use core::ops::ControlFlow;
 use hir::def::CtorKind;
 use hir::intravisit::{walk_expr, walk_stmt, Visitor};
-use hir::{Local, QPath};
+use hir::{LetStmt, QPath};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
@@ -321,7 +321,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             && let Some(expr) = block.expr
             && let hir::ExprKind::Path(QPath::Resolved(_, Path { res, .. })) = expr.kind
             && let Res::Local(local) = res
-            && let Node::Local(Local { init: Some(init), .. }) = self.tcx.parent_hir_node(*local)
+            && let Node::LetStmt(LetStmt { init: Some(init), .. }) =
+                self.tcx.parent_hir_node(*local)
         {
             fn collect_blocks<'hir>(expr: &hir::Expr<'hir>, blocks: &mut Vec<&hir::Block<'hir>>) {
                 match expr.kind {
@@ -585,7 +586,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
 
             fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
-                if let hir::StmtKind::Let(hir::Local {
+                if let hir::StmtKind::Let(LetStmt {
                     span,
                     pat: hir::Pat { .. },
                     ty: None,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8ba14d37982..656c7ffae19 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -48,6 +48,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
             let psess = ParseSess::with_silent_emitter(
                 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
                 format!("this error occurred on the command line: `--cfg={s}`"),
+                true,
             );
             let filename = FileName::cfg_spec_source_code(&s);
 
@@ -111,6 +112,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
         let psess = ParseSess::with_silent_emitter(
             vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
             format!("this error occurred on the command line: `--check-cfg={s}`"),
+            true,
         );
         let filename = FileName::cfg_spec_source_code(&s);
 
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index aba7f95487e..d173c3ac032 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -46,7 +46,7 @@ impl<'a> Cursor<'a> {
     /// If requested position doesn't exist, `EOF_CHAR` is returned.
     /// However, getting `EOF_CHAR` doesn't always mean actual end of file,
     /// it should be checked with `is_eof` method.
-    pub(crate) fn first(&self) -> char {
+    pub fn first(&self) -> char {
         // `.next()` optimizes better than `.nth(0)`
         self.chars.clone().next().unwrap_or(EOF_CHAR)
     }
@@ -59,6 +59,15 @@ impl<'a> Cursor<'a> {
         iter.next().unwrap_or(EOF_CHAR)
     }
 
+    /// Peeks the third symbol from the input stream without consuming it.
+    pub fn third(&self) -> char {
+        // `.next()` optimizes better than `.nth(1)`
+        let mut iter = self.chars.clone();
+        iter.next();
+        iter.next();
+        iter.next().unwrap_or(EOF_CHAR)
+    }
+
     /// Checks if there is nothing more to consume.
     pub(crate) fn is_eof(&self) -> bool {
         self.chars.as_str().is_empty()
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 8c0e5b17fd8..64ef30039a8 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -937,7 +937,7 @@ impl<'tcx> LateContext<'tcx> {
             }
             && let Some(init) = match parent_node {
                 hir::Node::Expr(expr) => Some(expr),
-                hir::Node::Local(hir::Local { init, .. }) => *init,
+                hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
                 _ => None,
             }
         {
@@ -982,7 +982,7 @@ impl<'tcx> LateContext<'tcx> {
             }
             && let Some(init) = match parent_node {
                 hir::Node::Expr(expr) => Some(expr),
-                hir::Node::Local(hir::Local { init, .. }) => *init,
+                hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
                 hir::Node::Item(item) => match item.kind {
                     hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
                         Some(self.tcx.hir().body(body_id).value)
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 506716e39a1..384bd353d75 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -238,7 +238,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         }
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         self.with_lint_attrs(l.hir_id, |cx| {
             lint_callback!(cx, check_local, l);
             hir_visit::walk_local(cx, l);
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index de642f373b5..9d4d75a646a 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -105,7 +105,7 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
     #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
         if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
             return;
         }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 26fc3f20b2c..5bb2942ad4b 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -354,7 +354,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
         intravisit::walk_variant(self, v);
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         self.add_id(l.hir_id);
         intravisit::walk_local(self, l);
     }
@@ -428,7 +428,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'
         intravisit::walk_variant(self, v);
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         self.add_id(l.hir_id);
         intravisit::walk_local(self, l);
     }
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 508f3e1ec31..3e93cc0be6a 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -15,7 +15,7 @@ macro_rules! late_lint_methods {
             fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>);
             fn check_item(a: &'tcx rustc_hir::Item<'tcx>);
             fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>);
-            fn check_local(a: &'tcx rustc_hir::Local<'tcx>);
+            fn check_local(a: &'tcx rustc_hir::LetStmt<'tcx>);
             fn check_block(a: &'tcx rustc_hir::Block<'tcx>);
             fn check_block_post(a: &'tcx rustc_hir::Block<'tcx>);
             fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>);
diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs
index b74430d8fa0..6222adf58ae 100644
--- a/compiler/rustc_lint/src/unit_bindings.rs
+++ b/compiler/rustc_lint/src/unit_bindings.rs
@@ -46,7 +46,7 @@ declare_lint! {
 declare_lint_pass!(UnitBindings => [UNIT_BINDINGS]);
 
 impl<'tcx> LateLintPass<'tcx> for UnitBindings {
-    fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::Local<'tcx>) {
+    fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::LetStmt<'tcx>) {
         // Suppress warning if user:
         // - explicitly ascribes a type to the pattern
         // - explicitly wrote `let pat = ();`
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index b544bc8a782..784fd4b3a3b 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -389,6 +389,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         None
     }
 
+    // The `dependency` type is determined by the command line arguments(`--extern`) and
+    // `private_dep`. However, sometimes the directly dependent crate is not specified by
+    // `--extern`, in this case, `private-dep` is none during loading. This is equivalent to the
+    // scenario where the command parameter is set to `public-dependency`
+    fn is_private_dep(&self, name: &str, private_dep: Option<bool>) -> bool {
+        self.sess.opts.externs.get(name).map_or(private_dep.unwrap_or(false), |e| e.is_private_dep)
+            && private_dep.unwrap_or(true)
+    }
+
     fn register_crate(
         &mut self,
         host_lib: Option<Library>,
@@ -404,14 +413,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-
-        let private_dep = self
-            .sess
-            .opts
-            .externs
-            .get(name.as_str())
-            .map_or(private_dep.unwrap_or(false), |e| e.is_private_dep)
-            && private_dep.unwrap_or(true);
+        let private_dep = self.is_private_dep(name.as_str(), private_dep);
 
         // Claim this crate number and cache it
         let cnum = self.cstore.intern_stable_crate_id(&crate_root)?;
@@ -601,14 +603,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         match result {
             (LoadResult::Previous(cnum), None) => {
+                // When `private_dep` is none, it indicates the directly dependent crate. If it is
+                // not specified by `--extern` on command line parameters, it may be
+                // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
+                // `public-dependency` here.
+                let private_dep = self.is_private_dep(name.as_str(), private_dep);
                 let data = self.cstore.get_crate_data_mut(cnum);
                 if data.is_proc_macro_crate() {
                     dep_kind = CrateDepKind::MacrosOnly;
                 }
                 data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind));
-                if let Some(private_dep) = private_dep {
-                    data.update_and_private_dep(private_dep);
-                }
+                data.update_and_private_dep(private_dep);
                 Ok(cnum)
             }
             (LoadResult::Loaded(library), host_library) => {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 1aabd296641..b69a295f010 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -211,6 +211,7 @@ provide! { tcx, def_id, other, cdata,
     generics_of => { table }
     inferred_outlives_of => { table_defaulted_array }
     super_predicates_of => { table }
+    implied_predicates_of => { table }
     type_of => { table }
     type_alias_is_lazy => { cdata.root.tables.type_alias_is_lazy.get(cdata, def_id.index) }
     variances_of => { table }
@@ -276,18 +277,6 @@ provide! { tcx, def_id, other, cdata,
             .map(|lazy| lazy.decode((cdata, tcx)))
             .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
     }
-    implied_predicates_of => {
-        cdata
-            .root
-            .tables
-            .implied_predicates_of
-            .get(cdata, def_id.index)
-            .map(|lazy| lazy.decode((cdata, tcx)))
-            .unwrap_or_else(|| {
-                debug_assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
-                tcx.super_predicates_of(def_id)
-            })
-    }
 
     associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 42724f7dd2b..61060038b50 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1435,6 +1435,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             if let DefKind::Trait = def_kind {
                 record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
+                record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id));
 
                 let module_children = self.tcx.module_children_local(local_id);
                 record_array!(self.tables.module_children_non_reexports[def_id] <-
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index a1bcee84d4c..53cb05198cd 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -567,7 +567,7 @@ impl<'hir> Map<'hir> {
                 }
                 // Ignore `return`s on the first iteration
                 Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
-                | Node::Local(_) => {
+                | Node::LetStmt(_) => {
                     return None;
                 }
                 _ => {}
@@ -906,7 +906,7 @@ impl<'hir> Map<'hir> {
             Node::Lifetime(lifetime) => lifetime.ident.span,
             Node::GenericParam(param) => param.span,
             Node::Infer(i) => i.span,
-            Node::Local(local) => local.span,
+            Node::LetStmt(local) => local.span,
             Node::Crate(item) => item.spans.inner_span,
             Node::WhereBoundPredicate(pred) => pred.span,
             Node::ArrayLenInfer(inf) => inf.span,
@@ -1163,7 +1163,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Node::Arm(_) => node_str("arm"),
         Node::Block(_) => node_str("block"),
         Node::Infer(_) => node_str("infer"),
-        Node::Local(_) => node_str("local"),
+        Node::LetStmt(_) => node_str("local"),
         Node::Ctor(ctor) => format!(
             "{id} (ctor {})",
             ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)),
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 48edbde68e5..e4dce2bdc9e 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -796,7 +796,7 @@ impl<'tcx> Body<'tcx> {
         }
 
         match rvalue {
-            Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {
+            Rvalue::NullaryOp(NullOp::UbChecks, _) => {
                 Some((tcx.sess.opts.debug_assertions as u128, targets))
             }
             Rvalue::Use(Operand::Constant(constant)) => {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 94751c44761..f0499cf344f 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::interpret::{
     Provenance,
 };
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, *};
+use rustc_middle::mir::*;
 use rustc_target::abi::Size;
 
 const INDENT: &str = "    ";
@@ -711,7 +711,7 @@ impl Debug for Statement<'_> {
             AscribeUserType(box (ref place, ref c_ty), ref variance) => {
                 write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
             }
-            Coverage(box mir::Coverage { ref kind }) => write!(fmt, "Coverage::{kind:?}"),
+            Coverage(ref kind) => write!(fmt, "Coverage::{kind:?}"),
             Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
             ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
             Nop => write!(fmt, "nop"),
@@ -944,7 +944,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                     NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
                     NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
                     NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
-                    NullOp::UbCheck(kind) => write!(fmt, "UbCheck({kind:?})"),
+                    NullOp::UbChecks => write!(fmt, "UbChecks()"),
                 }
             }
             ThreadLocalRef(did) => ty::tls::with(|tcx| {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 752f5845afb..12bf8efd73a 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -373,7 +373,7 @@ pub enum StatementKind<'tcx> {
     ///
     /// Interpreters and codegen backends that don't support coverage instrumentation
     /// can usually treat this as a no-op.
-    Coverage(Box<Coverage>),
+    Coverage(CoverageKind),
 
     /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
     /// This avoids adding a new block and a terminator for simple intrinsics.
@@ -519,12 +519,6 @@ pub enum FakeReadCause {
 
 #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
-pub struct Coverage {
-    pub kind: CoverageKind,
-}
-
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
 pub struct CopyNonOverlapping<'tcx> {
     pub src: Operand<'tcx>,
     pub dst: Operand<'tcx>,
@@ -1367,16 +1361,9 @@ pub enum NullOp<'tcx> {
     AlignOf,
     /// Returns the offset of a field
     OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
-    /// Returns whether we want to check for library UB or language UB at monomorphization time.
-    /// Both kinds of UB evaluate to `true` in codegen, and only library UB evalutes to `true` in
-    /// const-eval/Miri, because the interpreter has its own better checks for language UB.
-    UbCheck(UbKind),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
-pub enum UbKind {
-    LanguageUb,
-    LibraryUb,
+    /// Returns whether we want to check for UB.
+    /// This returns the value of `cfg!(debug_assertions)` at monomorphization time.
+    UbChecks,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -1465,5 +1452,6 @@ mod size_asserts {
     static_assert_size!(Place<'_>, 16);
     static_assert_size!(PlaceElem<'_>, 24);
     static_assert_size!(Rvalue<'_>, 40);
+    static_assert_size!(StatementKind<'_>, 16);
     // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index ac41b6c5732..56a0a623397 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -194,7 +194,7 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
                 tcx.types.usize
             }
-            Rvalue::NullaryOp(NullOp::UbCheck(_), _) => tcx.types.bool,
+            Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
                 AggregateKind::Tuple => {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index be960669ff4..3835bd371d9 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -156,10 +156,10 @@ macro_rules! make_mir_visitor {
 
             fn visit_coverage(
                 &mut self,
-                coverage: & $($mutability)? Coverage,
+                kind: & $($mutability)? coverage::CoverageKind,
                 location: Location,
             ) {
-                self.super_coverage(coverage, location);
+                self.super_coverage(kind, location);
             }
 
             fn visit_retag(
@@ -803,7 +803,7 @@ macro_rules! make_mir_visitor {
             }
 
             fn super_coverage(&mut self,
-                              _coverage: & $($mutability)? Coverage,
+                              _kind: & $($mutability)? coverage::CoverageKind,
                               _location: Location) {
             }
 
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index 2bd0e289731..18e45291e9a 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -107,9 +107,7 @@ impl<'tcx> CFG<'tcx> {
     /// This results in more accurate coverage reports for certain kinds of
     /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
     pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
-        let kind = StatementKind::Coverage(Box::new(Coverage {
-            kind: coverage::CoverageKind::SpanMarker,
-        }));
+        let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
         let stmt = Statement { source_info, kind };
         self.push(block, stmt);
     }
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs
index 0b8ec234dda..ab0043906b1 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs
@@ -127,9 +127,7 @@ impl Builder<'_, '_> {
 
             let marker_statement = mir::Statement {
                 source_info,
-                kind: mir::StatementKind::Coverage(Box::new(mir::Coverage {
-                    kind: CoverageKind::BlockMarker { id },
-                })),
+                kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
             };
             self.cfg.push(block, marker_statement);
 
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 3ca0eb4acd4..e73d945e0bb 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -433,7 +433,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
             | Rvalue::NullaryOp(
-                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbCheck(_),
+                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
                 _,
             ) => {}
         }
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index aaf2035fc21..da82f8de781 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -18,7 +18,7 @@
 
 use crate::MirPass;
 use rustc_middle::mir::coverage::CoverageKind;
-use rustc_middle::mir::{Body, BorrowKind, Coverage, Rvalue, StatementKind, TerminatorKind};
+use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
 
 pub struct CleanupPostBorrowck;
@@ -30,12 +30,11 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
                 match statement.kind {
                     StatementKind::AscribeUserType(..)
                     | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
-                    | StatementKind::Coverage(box Coverage {
+                    | StatementKind::Coverage(
                         // These kinds of coverage statements are markers inserted during
                         // MIR building, and are not needed after InstrumentCoverage.
-                        kind: CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
-                        ..
-                    })
+                        CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
+                    )
                     | StatementKind::FakeRead(..) => statement.make_nop(),
                     _ => (),
                 }
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 000b96ee801..e0bbd582d88 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -64,12 +64,9 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
         let mut by_move_body = body.clone();
         MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);
         dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
-        by_move_body.source = mir::MirSource {
-            instance: InstanceDef::CoroutineKindShim {
-                coroutine_def_id: coroutine_def_id.to_def_id(),
-            },
-            promoted: None,
-        };
+        by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim {
+            coroutine_def_id: coroutine_def_id.to_def_id(),
+        });
         body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body);
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 83189c6a50a..ae3b1a3d1af 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -15,7 +15,7 @@ use crate::MirPass;
 
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{
-    self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
+    self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
     TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
@@ -230,10 +230,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
     debug!("  injecting statement {counter_kind:?} for {bb:?}");
     let data = &mut mir_body[bb];
     let source_info = data.terminator().source_info;
-    let statement = Statement {
-        source_info,
-        kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind })),
-    };
+    let statement = Statement { source_info, kind: StatementKind::Coverage(counter_kind) };
     data.statements.insert(0, statement);
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 1de7b6f66a7..b5dd9dcc7b4 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::captures::Captures;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::{CounterId, CoverageKind};
-use rustc_middle::mir::{Body, Coverage, CoverageIdsInfo, Statement, StatementKind};
+use rustc_middle::mir::{Body, CoverageIdsInfo, Statement, StatementKind};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;
@@ -54,7 +54,7 @@ fn coverage_ids_info<'tcx>(
     let mir_body = tcx.instance_mir(instance_def);
 
     let max_counter_id = all_coverage_in_mir_body(mir_body)
-        .filter_map(|coverage| match coverage.kind {
+        .filter_map(|kind| match *kind {
             CoverageKind::CounterIncrement { id } => Some(id),
             _ => None,
         })
@@ -66,12 +66,10 @@ fn coverage_ids_info<'tcx>(
 
 fn all_coverage_in_mir_body<'a, 'tcx>(
     body: &'a Body<'tcx>,
-) -> impl Iterator<Item = &'a Coverage> + Captures<'tcx> {
+) -> impl Iterator<Item = &'a CoverageKind> + Captures<'tcx> {
     body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| {
         match statement.kind {
-            StatementKind::Coverage(box ref coverage) if !is_inlined(body, statement) => {
-                Some(coverage)
-            }
+            StatementKind::Coverage(ref kind) if !is_inlined(body, statement) => Some(kind),
             _ => None,
         }
     })
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 3f6a4156044..adb0c9f1929 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -187,9 +187,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
         // for their parent `BasicBlock`.
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
-        // Ignore `ConstEvalCounter`s
         | StatementKind::ConstEvalCounter
-        // Ignore `Nop`s
         | StatementKind::Nop => None,
 
         // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
@@ -211,30 +209,28 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
         StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None,
 
         // Retain spans from most other statements.
-        StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
+        StatementKind::FakeRead(_)
         | StatementKind::Intrinsic(..)
-        | StatementKind::Coverage(box mir::Coverage {
+        | StatementKind::Coverage(
             // The purpose of `SpanMarker` is to be matched and accepted here.
-            kind: CoverageKind::SpanMarker
-        })
+            CoverageKind::SpanMarker,
+        )
         | StatementKind::Assign(_)
         | StatementKind::SetDiscriminant { .. }
         | StatementKind::Deinit(..)
         | StatementKind::Retag(_, _)
         | StatementKind::PlaceMention(..)
-        | StatementKind::AscribeUserType(_, _) => {
-            Some(statement.source_info.span)
-        }
+        | StatementKind::AscribeUserType(_, _) => Some(statement.source_info.span),
 
-        StatementKind::Coverage(box mir::Coverage {
-            // Block markers are used for branch coverage, so ignore them here.
-            kind: CoverageKind::BlockMarker {..}
-        }) => None,
+        // Block markers are used for branch coverage, so ignore them here.
+        StatementKind::Coverage(CoverageKind::BlockMarker { .. }) => None,
 
-        StatementKind::Coverage(box mir::Coverage {
-            // These coverage statements should not exist prior to coverage instrumentation.
-            kind: CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. }
-        }) => bug!("Unexpected coverage statement found during coverage instrumentation: {statement:?}"),
+        // These coverage statements should not exist prior to coverage instrumentation.
+        StatementKind::Coverage(
+            CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. },
+        ) => bug!(
+            "Unexpected coverage statement found during coverage instrumentation: {statement:?}"
+        ),
     }
 }
 
@@ -382,9 +378,7 @@ pub(super) fn extract_branch_mappings(
     // Fill out the mapping from block marker IDs to their enclosing blocks.
     for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
         for statement in &data.statements {
-            if let StatementKind::Coverage(coverage) = &statement.kind
-                && let CoverageKind::BlockMarker { id } = coverage.kind
-            {
+            if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind {
                 block_markers[id] = Some(bb);
             }
         }
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index fdc81c0a99e..59d6d89cf1f 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -487,7 +487,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     NullOp::OffsetOf(fields) => {
                         layout.offset_of_subfield(&self.ecx, fields.iter()).bytes()
                     }
-                    NullOp::UbCheck(_) => return None,
+                    NullOp::UbChecks => return None,
                 };
                 let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
                 let imm = ImmTy::try_from_uint(val, usize_layout)?;
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 4ec76eec3a9..78c0615b165 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -213,6 +213,7 @@ impl<'tcx> Inliner<'tcx> {
             MirPhase::Runtime(RuntimePhase::Optimized),
             self.param_env,
             &callee_body,
+            &caller_body,
         )
         .is_empty()
         {
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 6b13725b386..a20958e74df 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -639,7 +639,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     NullOp::OffsetOf(fields) => {
                         op_layout.offset_of_subfield(self, fields.iter()).bytes()
                     }
-                    NullOp::UbCheck(_) => return None,
+                    NullOp::UbChecks => return None,
                 };
                 ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
             }
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 1bab240ef50..7d4c1b9c21a 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -20,30 +20,13 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                     sym::unreachable => {
                         terminator.kind = TerminatorKind::Unreachable;
                     }
-                    sym::check_language_ub => {
+                    sym::ub_checks => {
                         let target = target.unwrap();
                         block.statements.push(Statement {
                             source_info: terminator.source_info,
                             kind: StatementKind::Assign(Box::new((
                                 *destination,
-                                Rvalue::NullaryOp(
-                                    NullOp::UbCheck(UbKind::LanguageUb),
-                                    tcx.types.bool,
-                                ),
-                            ))),
-                        });
-                        terminator.kind = TerminatorKind::Goto { target };
-                    }
-                    sym::check_library_ub => {
-                        let target = target.unwrap();
-                        block.statements.push(Statement {
-                            source_info: terminator.source_info,
-                            kind: StatementKind::Assign(Box::new((
-                                *destination,
-                                Rvalue::NullaryOp(
-                                    NullOp::UbCheck(UbKind::LibraryUb),
-                                    tcx.types.bool,
-                                ),
+                                Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool),
                             ))),
                         });
                         terminator.kind = TerminatorKind::Goto { target };
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 202ea571985..2951897ebd6 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -446,7 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 NullOp::SizeOf => {}
                 NullOp::AlignOf => {}
                 NullOp::OffsetOf(_) => {}
-                NullOp::UbCheck(_) => {}
+                NullOp::UbChecks => {}
             },
 
             Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index bd23b90fc31..16d8453ea24 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -239,7 +239,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             // FIXME: We should investigate the perf implications of not uniquifying
             // `ReErased`. We may be able to short-circuit registering region
             // obligations if we encounter a `ReErased` on one side, for example.
-            ty::ReStatic | ty::ReErased => match self.canonicalize_mode {
+            ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
                 CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
                 CanonicalizeMode::Response { .. } => return r,
             },
@@ -277,7 +277,6 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
                     }
                 }
             }
-            ty::ReError(_) => return r,
         };
 
         let existing_bound_var = match self.canonicalize_mode {
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index e1d26f090e0..aa735f3de1f 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -568,7 +568,7 @@ parse_more_than_one_char = character literal may only contain one codepoint
     .remove_non = consider removing the non-printing characters
     .use_double_quotes = if you meant to write a {$is_byte ->
         [true] byte string
-        *[false] `str`
+        *[false] string
         } literal, use double quotes
 
 parse_multiple_skipped_lines = multiple lines skipped by escaped newline
@@ -833,6 +833,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown
     .label = unknown prefix
     .note =  prefixed identifiers and literals are reserved since Rust 2021
     .suggestion_br = use `br` for a raw byte string
+    .suggestion_str = if you meant to write a string literal, use double quotes
     .suggestion_whitespace = consider inserting whitespace here
 
 parse_unknown_start_of_token = unknown start of token: {$escaped}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 5cad3a568ee..20ebfc6691b 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1987,6 +1987,17 @@ pub enum UnknownPrefixSugg {
         style = "verbose"
     )]
     Whitespace(#[primary_span] Span),
+    #[multipart_suggestion(
+        parse_suggestion_str,
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
+    MeantStr {
+        #[suggestion_part(code = "\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
+    },
 }
 
 #[derive(Diagnostic)]
@@ -2198,12 +2209,21 @@ pub enum MoreThanOneCharSugg {
         ch: String,
     },
     #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
-    Quotes {
+    QuotesFull {
         #[primary_span]
         span: Span,
         is_byte: bool,
         sugg: String,
     },
+    #[multipart_suggestion(parse_use_double_quotes, applicability = "machine-applicable")]
+    Quotes {
+        #[suggestion_part(code = "{prefix}\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
+        is_byte: bool,
+        prefix: &'static str,
+    },
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index f57945a52df..63b2b47630b 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -63,6 +63,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>(
         cursor,
         override_span,
         nbsp_is_whitespace: false,
+        last_lifetime: None,
     };
     let (stream, res, unmatched_delims) =
         tokentrees::TokenTreesReader::parse_all_token_trees(string_reader);
@@ -105,6 +106,10 @@ struct StringReader<'psess, 'src> {
     /// in this file, it's safe to treat further occurrences of the non-breaking
     /// space character as whitespace.
     nbsp_is_whitespace: bool,
+
+    /// Track the `Span` for the leading `'` of the last lifetime. Used for
+    /// diagnostics to detect possible typo where `"` was meant.
+    last_lifetime: Option<Span>,
 }
 
 impl<'psess, 'src> StringReader<'psess, 'src> {
@@ -130,6 +135,18 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
 
             debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
 
+            if let rustc_lexer::TokenKind::Semi
+            | rustc_lexer::TokenKind::LineComment { .. }
+            | rustc_lexer::TokenKind::BlockComment { .. }
+            | rustc_lexer::TokenKind::CloseParen
+            | rustc_lexer::TokenKind::CloseBrace
+            | rustc_lexer::TokenKind::CloseBracket = token.kind
+            {
+                // Heuristic: we assume that it is unlikely we're dealing with an unterminated
+                // string surrounded by single quotes.
+                self.last_lifetime = None;
+            }
+
             // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a
             // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs
             // additional validation.
@@ -247,6 +264,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
                     // expansion purposes. See #12512 for the gory details of why
                     // this is necessary.
                     let lifetime_name = self.str_from(start);
+                    self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1)));
                     if starts_with_number {
                         let span = self.mk_sp(start, self.pos);
                         self.dcx().struct_err("lifetimes cannot start with a number")
@@ -395,10 +413,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
         match kind {
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
-                    self.dcx()
+                    let mut err = self
+                        .dcx()
                         .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal")
-                        .with_code(E0762)
-                        .emit()
+                        .with_code(E0762);
+                    if let Some(lt_sp) = self.last_lifetime {
+                        err.multipart_suggestion(
+                            "if you meant to write a string literal, use double quotes",
+                            vec![
+                                (lt_sp, "\"".to_string()),
+                                (self.mk_sp(start, start + BytePos(1)), "\"".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    err.emit()
                 }
                 self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' '
             }
@@ -669,15 +698,33 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
         let expn_data = prefix_span.ctxt().outer_expn_data();
 
         if expn_data.edition >= Edition::Edition2021 {
+            let mut silence = false;
             // In Rust 2021, this is a hard error.
             let sugg = if prefix == "rb" {
                 Some(errors::UnknownPrefixSugg::UseBr(prefix_span))
             } else if expn_data.is_root() {
-                Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi()))
+                if self.cursor.first() == '\''
+                    && let Some(start) = self.last_lifetime
+                    && self.cursor.third() != '\''
+                {
+                    // An "unclosed `char`" error will be emitted already, silence redundant error.
+                    silence = true;
+                    Some(errors::UnknownPrefixSugg::MeantStr {
+                        start,
+                        end: self.mk_sp(self.pos, self.pos + BytePos(1)),
+                    })
+                } else {
+                    Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi()))
+                }
             } else {
                 None
             };
-            self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
+            let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg };
+            if silence {
+                self.dcx().create_err(err).delay_as_bug();
+            } else {
+                self.dcx().emit_err(err);
+            }
         } else {
             // Before Rust 2021, only emit a lint for migration.
             self.psess.buffer_lint_with_diagnostic(
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 3ebad6a9fd7..fa242a32a18 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -95,11 +95,21 @@ pub(crate) fn emit_unescape_error(
                     }
                     escaped.push(c);
                 }
-                let sugg = format!("{prefix}\"{escaped}\"");
-                MoreThanOneCharSugg::Quotes {
-                    span: full_lit_span,
-                    is_byte: mode == Mode::Byte,
-                    sugg,
+                if escaped.len() != lit.len() || full_lit_span.is_empty() {
+                    let sugg = format!("{prefix}\"{escaped}\"");
+                    MoreThanOneCharSugg::QuotesFull {
+                        span: full_lit_span,
+                        is_byte: mode == Mode::Byte,
+                        sugg,
+                    }
+                } else {
+                    MoreThanOneCharSugg::Quotes {
+                        start: full_lit_span
+                            .with_hi(full_lit_span.lo() + BytePos((prefix.len() + 1) as u32)),
+                        end: full_lit_span.with_lo(full_lit_span.hi() - BytePos(1)),
+                        is_byte: mode == Mode::Byte,
+                        prefix,
+                    }
                 }
             });
             dcx.emit_err(UnescapeError::MoreThanOneChar {
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d0dba938b3b..e6e52648d6f 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -264,7 +264,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_foreign_item(self, i)
     }
 
-    fn visit_local(&mut self, l: &'v hir::Local<'v>) {
+    fn visit_local(&mut self, l: &'v hir::LetStmt<'v>) {
         self.record("Local", Id::Node(l.hir_id), l);
         hir_visit::walk_local(self, l)
     }
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index f0c3f7a385d..125084f4750 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -342,7 +342,7 @@ impl<'tcx> IrMaps<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         self.add_from_pat(local.pat);
         if local.els.is_some() {
             self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id));
@@ -1350,7 +1350,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 // Checking for error conditions
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         self.check_unused_vars_in_pat(local.pat, None, None, |spans, hir_id, ln, var| {
             if local.init.is_some() {
                 self.warn_about_dead_assign(spans, hir_id, ln, var);
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index c73fdd59609..41d63407418 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1209,7 +1209,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         intravisit::walk_pat(self, pattern);
     }
 
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         if let Some(init) = local.init {
             if self.check_expr_pat_type(init.hir_id, init.span) {
                 // Do not report duplicate errors for `let x = y`.
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 2553df33cc7..93839fa1186 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -44,6 +44,10 @@ pub struct FieldInfo {
     pub offset: u64,
     pub size: u64,
     pub align: u64,
+    /// Name of the type of this field.
+    /// Present only if the creator thought that this would be important for identifying the field,
+    /// typically because the field name is uninformative.
+    pub type_name: Option<Symbol>,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -192,7 +196,7 @@ impl CodeStats {
                 fields.sort_by_key(|f| (f.offset, f.size));
 
                 for field in fields {
-                    let FieldInfo { kind, ref name, offset, size, align } = field;
+                    let FieldInfo { kind, ref name, offset, size, align, type_name } = field;
 
                     if offset > min_offset {
                         let pad = offset - min_offset;
@@ -201,21 +205,27 @@ impl CodeStats {
 
                     if offset < min_offset {
                         // If this happens it's probably a union.
-                        println!(
+                        print!(
                             "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
                                   offset: {offset} bytes, \
                                   alignment: {align} bytes"
                         );
                     } else if info.packed || offset == min_offset {
-                        println!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
+                        print!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
                     } else {
                         // Include field alignment in output only if it caused padding injection
-                        println!(
+                        print!(
                             "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
                                   alignment: {align} bytes"
                         );
                     }
 
+                    if let Some(type_name) = type_name {
+                        println!(", type: {type_name}");
+                    } else {
+                        println!();
+                    }
+
                     min_offset = offset + size;
                 }
             }
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 5434bbe0b98..f6053f43fbd 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -269,7 +269,11 @@ impl ParseSess {
         }
     }
 
-    pub fn with_silent_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self {
+    pub fn with_silent_emitter(
+        locale_resources: Vec<&'static str>,
+        fatal_note: String,
+        emit_fatal_diagnostic: bool,
+    ) -> Self {
         let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let emitter = Box::new(HumanEmitter::new(
@@ -281,6 +285,7 @@ impl ParseSess {
             fallback_bundle,
             fatal_dcx,
             fatal_note: Some(fatal_note),
+            emit_fatal_diagnostic,
         }))
         .disable_warnings();
         ParseSess::with_dcx(dcx, sm)
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index c0876adf905..b6a722da602 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -251,19 +251,13 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
     type T = stable_mir::mir::NullOp;
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         use rustc_middle::mir::NullOp::*;
-        use rustc_middle::mir::UbKind;
         match self {
             SizeOf => stable_mir::mir::NullOp::SizeOf,
             AlignOf => stable_mir::mir::NullOp::AlignOf,
             OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
                 indices.iter().map(|idx| idx.stable(tables)).collect(),
             ),
-            UbCheck(UbKind::LanguageUb) => {
-                stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LanguageUb)
-            }
-            UbCheck(UbKind::LibraryUb) => {
-                stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LibraryUb)
-            }
+            UbChecks => stable_mir::mir::NullOp::UbChecks,
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b6c07e8737f..73fcd2a76df 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -518,8 +518,6 @@ symbols! {
         cfi,
         cfi_encoding,
         char,
-        check_language_ub,
-        check_library_ub,
         client,
         clippy,
         clobber_abi,
@@ -1836,6 +1834,7 @@ symbols! {
         type_macros,
         type_name,
         type_privacy_lints,
+        typed_swap,
         u128,
         u128_legacy_const_max,
         u128_legacy_const_min,
@@ -1866,6 +1865,7 @@ symbols! {
         u8_legacy_fn_max_value,
         u8_legacy_fn_min_value,
         u8_legacy_mod,
+        ub_checks,
         unaligned_volatile_load,
         unaligned_volatile_store,
         unboxed_closures,
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index e8763e49e62..3bf564a4a16 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -36,7 +36,7 @@ pub fn typeid_for_instance<'tcx>(
     instance: &Instance<'tcx>,
     options: TypeIdOptions,
 ) -> String {
-    typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
+    typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options)
 }
 
 /// Returns a KCFI type metadata identifier for the specified FnAbi.
@@ -61,6 +61,6 @@ pub fn kcfi_typeid_for_instance<'tcx>(
     // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
     // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
     let mut hash: XxHash64 = Default::default();
-    hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
+    hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options).as_bytes());
     hash.finish() as u32
 }
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 07a382d161d..367fec0e8fc 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -178,14 +178,14 @@ fn encode_fnsig<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options);
+    let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options);
     s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
 
     // Encode the parameter types
     let tys = fn_sig.inputs();
     if !tys.is_empty() {
         for ty in tys {
-            let ty = transform_ty(tcx, *ty, transform_ty_options);
+            let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options);
             s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
         }
 
@@ -767,11 +767,12 @@ fn transform_predicates<'tcx>(
 fn transform_args<'tcx>(
     tcx: TyCtxt<'tcx>,
     args: GenericArgsRef<'tcx>,
+    parents: &mut Vec<Ty<'tcx>>,
     options: TransformTyOptions,
 ) -> GenericArgsRef<'tcx> {
     let args = args.iter().map(|arg| match arg.unpack() {
         GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(),
-        GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(),
+        GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(),
         _ => arg,
     });
     tcx.mk_args_from_iter(args)
@@ -781,9 +782,12 @@ fn transform_args<'tcx>(
 // c_void types into unit types unconditionally, generalizes pointers if
 // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
 // TransformTyOptions::NORMALIZE_INTEGERS option is set.
-fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
-    let mut ty = ty;
-
+fn transform_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mut ty: Ty<'tcx>,
+    parents: &mut Vec<Ty<'tcx>>,
+    options: TransformTyOptions,
+) -> Ty<'tcx> {
     match ty.kind() {
         ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {}
 
@@ -843,17 +847,20 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
         _ if ty.is_unit() => {}
 
         ty::Tuple(tys) => {
-            ty = Ty::new_tup_from_iter(tcx, tys.iter().map(|ty| transform_ty(tcx, ty, options)));
+            ty = Ty::new_tup_from_iter(
+                tcx,
+                tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)),
+            );
         }
 
         ty::Array(ty0, len) => {
             let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
 
-            ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, options), len);
+            ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len);
         }
 
         ty::Slice(ty0) => {
-            ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, options));
+            ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options));
         }
 
         ty::Adt(adt_def, args) => {
@@ -862,7 +869,8 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
             } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
             {
                 ty = Ty::new_adt(tcx, *adt_def, ty::List::empty());
-            } else if adt_def.repr().transparent() && adt_def.is_struct() {
+            } else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty)
+            {
                 // Don't transform repr(transparent) types with an user-defined CFI encoding to
                 // preserve the user-defined CFI encoding.
                 if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
@@ -881,38 +889,48 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     // Generalize any repr(transparent) user-defined type that is either a pointer
                     // or reference, and either references itself or any other type that contains or
                     // references itself, to avoid a reference cycle.
+
+                    // If the self reference is not through a pointer, for example, due
+                    // to using `PhantomData`, need to skip normalizing it if we hit it again.
+                    parents.push(ty);
                     if ty0.is_any_ptr() && ty0.contains(ty) {
                         ty = transform_ty(
                             tcx,
                             ty0,
+                            parents,
                             options | TransformTyOptions::GENERALIZE_POINTERS,
                         );
                     } else {
-                        ty = transform_ty(tcx, ty0, options);
+                        ty = transform_ty(tcx, ty0, parents, options);
                     }
+                    parents.pop();
                 } else {
                     // Transform repr(transparent) types without non-ZST field into ()
                     ty = Ty::new_unit(tcx);
                 }
             } else {
-                ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, options));
+                ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options));
             }
         }
 
         ty::FnDef(def_id, args) => {
-            ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, options));
+            ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options));
         }
 
         ty::Closure(def_id, args) => {
-            ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, options));
+            ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options));
         }
 
         ty::CoroutineClosure(def_id, args) => {
-            ty = Ty::new_coroutine_closure(tcx, *def_id, transform_args(tcx, args, options));
+            ty = Ty::new_coroutine_closure(
+                tcx,
+                *def_id,
+                transform_args(tcx, args, parents, options),
+            );
         }
 
         ty::Coroutine(def_id, args) => {
-            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options));
+            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options));
         }
 
         ty::Ref(region, ty0, ..) => {
@@ -924,9 +942,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                 }
             } else {
                 if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, options));
+                    ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
                 } else {
-                    ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, options));
+                    ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
                 }
             }
         }
@@ -940,9 +958,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                 }
             } else {
                 if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, options));
+                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, options));
+                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
                 }
             }
         }
@@ -955,9 +973,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     .skip_binder()
                     .inputs()
                     .iter()
-                    .map(|ty| transform_ty(tcx, *ty, options))
+                    .map(|ty| transform_ty(tcx, *ty, parents, options))
                     .collect();
-                let output = transform_ty(tcx, fn_sig.skip_binder().output(), options);
+                let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options);
                 ty = Ty::new_fn_ptr(
                     tcx,
                     ty::Binder::bind_with_vars(
@@ -987,6 +1005,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
             ty = transform_ty(
                 tcx,
                 tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty),
+                parents,
                 options,
             );
         }
@@ -1037,7 +1056,7 @@ pub fn typeid_for_fnabi<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options);
+    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options);
     typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
 
     // Encode the parameter types
@@ -1049,7 +1068,7 @@ pub fn typeid_for_fnabi<'tcx>(
         let mut pushed_arg = false;
         for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
             pushed_arg = true;
-            let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
+            let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
         if !pushed_arg {
@@ -1062,7 +1081,8 @@ pub fn typeid_for_fnabi<'tcx>(
             if fn_abi.args[n].mode == PassMode::Ignore {
                 continue;
             }
-            let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options);
+            let ty =
+                transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
 
@@ -1088,11 +1108,15 @@ pub fn typeid_for_fnabi<'tcx>(
 /// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
 pub fn typeid_for_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
-    instance: &Instance<'tcx>,
+    mut instance: Instance<'tcx>,
     options: TypeIdOptions,
 ) -> String {
+    if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
+        instance.args = strip_receiver_auto(tcx, instance.args)
+    }
+
     let fn_abi = tcx
-        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty())))
+        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
         .unwrap_or_else(|instance| {
             bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
         });
@@ -1138,3 +1162,23 @@ pub fn typeid_for_instance<'tcx>(
 
     typeid_for_fnabi(tcx, fn_abi, options)
 }
+
+fn strip_receiver_auto<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    args: ty::GenericArgsRef<'tcx>,
+) -> ty::GenericArgsRef<'tcx> {
+    let ty = args.type_at(0);
+    let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
+        bug!("Tried to strip auto traits from non-dynamic type {ty}");
+    };
+    let filtered_preds =
+        if preds.principal().is_some() {
+            tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
+                !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
+            }))
+        } else {
+            ty::List::empty()
+        };
+    let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind);
+    tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
+}
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 97132311a5c..70528c1222c 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -27,32 +27,28 @@ impl AArch64InlineAsmRegClass {
         None
     }
 
-    pub fn suggest_modifier(
-        self,
-        _arch: InlineAsmArch,
-        ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    pub fn suggest_modifier(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
         match self {
             Self::reg => match ty.size().bits() {
                 64 => None,
-                _ => Some(('w', "w0")),
+                _ => Some(('w', "w0", 32).into()),
             },
             Self::vreg | Self::vreg_low16 => match ty.size().bits() {
-                8 => Some(('b', "b0")),
-                16 => Some(('h', "h0")),
-                32 => Some(('s', "s0")),
-                64 => Some(('d', "d0")),
-                128 => Some(('q', "q0")),
+                8 => Some(('b', "b0", 8).into()),
+                16 => Some(('h', "h0", 16).into()),
+                32 => Some(('s', "s0", 32).into()),
+                64 => Some(('d', "d0", 64).into()),
+                128 => Some(('q', "q0", 128).into()),
                 _ => None,
             },
             Self::preg => None,
         }
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         match self {
-            Self::reg => Some(('x', "x0")),
-            Self::vreg | Self::vreg_low16 => Some(('v', "v0")),
+            Self::reg => Some(('x', "x0", 64).into()),
+            Self::vreg | Self::vreg_low16 => Some(('v', "v0", 128).into()),
             Self::preg => None,
         }
     }
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index 514e30ae020..f56dbac708b 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -35,11 +35,11 @@ impl ArmInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
index 9a96a61f5b2..eab38a4a4f4 100644
--- a/compiler/rustc_target/src/asm/avr.rs
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -29,11 +29,11 @@ impl AvrInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
index 3b03766a089..9bc94274675 100644
--- a/compiler/rustc_target/src/asm/bpf.rs
+++ b/compiler/rustc_target/src/asm/bpf.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl BpfInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs
index db3d8106040..64607ee4b81 100644
--- a/compiler/rustc_target/src/asm/csky.rs
+++ b/compiler/rustc_target/src/asm/csky.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl CSKYInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index d20270ac9e9..19da7b80848 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -22,11 +22,11 @@ impl HexagonInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
index 9d1a4f3eeea..15d0f54ce3b 100644
--- a/compiler/rustc_target/src/asm/loongarch.rs
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl LoongArchInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/m68k.rs b/compiler/rustc_target/src/asm/m68k.rs
index 8c857550cf2..ac94dcc03dc 100644
--- a/compiler/rustc_target/src/asm/m68k.rs
+++ b/compiler/rustc_target/src/asm/m68k.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -24,11 +24,11 @@ impl M68kInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index 4e7c2eb1bf8..0ac1a43ae18 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl MipsInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index a11884bea26..2e04dca98c5 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -6,6 +6,18 @@ use rustc_span::Symbol;
 use std::fmt;
 use std::str::FromStr;
 
+pub struct ModifierInfo {
+    pub modifier: char,
+    pub result: &'static str,
+    pub size: u64,
+}
+
+impl From<(char, &'static str, u64)> for ModifierInfo {
+    fn from((modifier, result, size): (char, &'static str, u64)) -> Self {
+        Self { modifier, result, size }
+    }
+}
+
 macro_rules! def_reg_class {
     ($arch:ident $arch_regclass:ident {
         $(
@@ -512,11 +524,7 @@ impl InlineAsmRegClass {
     /// Such suggestions are useful if a type smaller than the full register
     /// size is used and a modifier can be used to point to the subregister of
     /// the correct size.
-    pub fn suggest_modifier(
-        self,
-        arch: InlineAsmArch,
-        ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
         match self {
             Self::X86(r) => r.suggest_modifier(arch, ty),
             Self::Arm(r) => r.suggest_modifier(arch, ty),
@@ -545,7 +553,7 @@ impl InlineAsmRegClass {
     /// This is only needed when the register class can suggest a modifier, so
     /// that the user can be shown how to get the default behavior without a
     /// warning.
-    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<ModifierInfo> {
         match self {
             Self::X86(r) => r.default_modifier(arch),
             Self::Arm(r) => r.default_modifier(arch),
diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs
index a27d6390a72..439f3ba0b57 100644
--- a/compiler/rustc_target/src/asm/msp430.rs
+++ b/compiler/rustc_target/src/asm/msp430.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -22,11 +22,11 @@ impl Msp430InlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs
index 8e1e91e7c5f..57aa50fceb8 100644
--- a/compiler/rustc_target/src/asm/nvptx.rs
+++ b/compiler/rustc_target/src/asm/nvptx.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
@@ -23,11 +23,11 @@ impl NvptxInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index d3ccb30350a..4e8cbe34de9 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -26,11 +26,11 @@ impl PowerPCInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index dea6d50fe2b..2505d36f5b8 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -26,11 +26,11 @@ impl RiscVInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index b8afeb824d8..6bc668454b1 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -24,11 +24,11 @@ impl S390xInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs
index 31073da10b2..d13a6131f9a 100644
--- a/compiler/rustc_target/src/asm/spirv.rs
+++ b/compiler/rustc_target/src/asm/spirv.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
@@ -21,11 +21,11 @@ impl SpirVInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
index f095b7c6e11..eb0b23ef43d 100644
--- a/compiler/rustc_target/src/asm/wasm.rs
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
@@ -21,11 +21,11 @@ impl WasmInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 3902dac7ff6..3b5da8806cc 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -53,32 +53,28 @@ impl X86InlineAsmRegClass {
         }
     }
 
-    pub fn suggest_modifier(
-        self,
-        arch: InlineAsmArch,
-        ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
         match self {
             Self::reg => match ty.size().bits() {
-                16 => Some(('x', "ax")),
-                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
+                16 => Some(('x', "ax", 16).into()),
+                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()),
                 _ => None,
             },
             Self::reg_abcd => match ty.size().bits() {
-                16 => Some(('x', "ax")),
-                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
+                16 => Some(('x', "ax", 16).into()),
+                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()),
                 _ => None,
             },
             Self::reg_byte => None,
             Self::xmm_reg => None,
             Self::ymm_reg => match ty.size().bits() {
                 256 => None,
-                _ => Some(('x', "xmm0")),
+                _ => Some(('x', "xmm0", 128).into()),
             },
             Self::zmm_reg => match ty.size().bits() {
                 512 => None,
-                256 => Some(('y', "ymm0")),
-                _ => Some(('x', "xmm0")),
+                256 => Some(('y', "ymm0", 256).into()),
+                _ => Some(('x', "xmm0", 128).into()),
             },
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
@@ -86,19 +82,19 @@ impl X86InlineAsmRegClass {
         }
     }
 
-    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<ModifierInfo> {
         match self {
             Self::reg | Self::reg_abcd => {
                 if arch == InlineAsmArch::X86_64 {
-                    Some(('r', "rax"))
+                    Some(('r', "rax", 64).into())
                 } else {
-                    Some(('e', "eax"))
+                    Some(('e', "eax", 32).into())
                 }
             }
             Self::reg_byte => None,
-            Self::xmm_reg => Some(('x', "xmm0")),
-            Self::ymm_reg => Some(('y', "ymm0")),
-            Self::zmm_reg => Some(('z', "zmm0")),
+            Self::xmm_reg => Some(('x', "xmm0", 128).into()),
+            Self::ymm_reg => Some(('y', "ymm0", 256).into()),
+            Self::zmm_reg => Some(('z', "zmm0", 512).into()),
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
             Self::tmm_reg => None,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index bd737e6ab82..28f4f81e7d8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -768,7 +768,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
             // Different to previous arm because one is `&hir::Local` and the other
             // is `P<hir::Local>`.
-            hir::Node::Local(local) => get_name(err, &local.pat.kind),
+            hir::Node::LetStmt(local) => get_name(err, &local.pat.kind),
             _ => None,
         }
     }
@@ -930,7 +930,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
             return;
         };
-        let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
+        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
             self.tcx.parent_hir_node(pat.hir_id)
         else {
             return;
@@ -1562,7 +1562,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let Res::Local(hir_id) = path.res
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id)
-                && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
+                && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
                 && let None = local.ty
                 && let Some(binding_expr) = local.init
             {
@@ -2966,7 +2966,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     err.downgrade_to_delayed_bug();
                 }
                 match tcx.parent_hir_node(hir_id) {
-                    Node::Local(hir::Local { ty: Some(ty), .. }) => {
+                    Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
                         err.span_suggestion_verbose(
                             ty.span.shrink_to_lo(),
                             "consider borrowing here",
@@ -2975,7 +2975,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         );
                         err.note("all local variables must have a statically known size");
                     }
-                    Node::Local(hir::Local {
+                    Node::LetStmt(hir::LetStmt {
                         init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
                         ..
                     }) => {
@@ -3867,7 +3867,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: Res::Local(hir_id), .. } = path
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
-                && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
+                && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
                 && let Some(binding_expr) = local.init
             {
                 // If the expression we're calling on is a binding, we want to point at the
@@ -4128,7 +4128,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             {
                 let parent = self.tcx.parent_hir_node(binding.hir_id);
                 // We've reached the root of the method call chain...
-                if let hir::Node::Local(local) = parent
+                if let hir::Node::LetStmt(local) = parent
                     && let Some(binding_expr) = local.init
                 {
                     // ...and it is a binding. Get the binding creation and continue the chain.
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 01f9c8bb5d1..9444cf8248e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1272,7 +1272,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             {
                 let parent = self.tcx.parent_hir_node(binding.hir_id);
                 // We've reached the root of the method call chain...
-                if let hir::Node::Local(local) = parent
+                if let hir::Node::LetStmt(local) = parent
                     && let Some(binding_expr) = local.init
                 {
                     // ...and it is a binding. Get the binding creation and continue the chain.
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 48e76d50be1..9c3d39307b2 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -10,6 +10,7 @@ use rustc_middle::ty::layout::{
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
+use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::*;
 
@@ -1007,6 +1008,7 @@ fn variant_info_for_adt<'tcx>(
                     offset: offset.bytes(),
                     size: field_layout.size.bytes(),
                     align: field_layout.align.abi.bytes(),
+                    type_name: None,
                 }
             })
             .collect();
@@ -1090,6 +1092,7 @@ fn variant_info_for_coroutine<'tcx>(
                 offset: offset.bytes(),
                 size: field_layout.size.bytes(),
                 align: field_layout.align.abi.bytes(),
+                type_name: None,
             }
         })
         .collect();
@@ -1104,19 +1107,24 @@ fn variant_info_for_coroutine<'tcx>(
                 .iter()
                 .enumerate()
                 .map(|(field_idx, local)| {
+                    let field_name = coroutine.field_names[*local];
                     let field_layout = variant_layout.field(cx, field_idx);
                     let offset = variant_layout.fields.offset(field_idx);
                     // The struct is as large as the last field's end
                     variant_size = variant_size.max(offset + field_layout.size);
                     FieldInfo {
                         kind: FieldKind::CoroutineLocal,
-                        name: coroutine.field_names[*local].unwrap_or(Symbol::intern(&format!(
+                        name: field_name.unwrap_or(Symbol::intern(&format!(
                             ".coroutine_field{}",
                             local.as_usize()
                         ))),
                         offset: offset.bytes(),
                         size: field_layout.size.bytes(),
                         align: field_layout.align.abi.bytes(),
+                        // Include the type name if there is no field name, or if the name is the
+                        // __awaitee placeholder symbol which means a child future being `.await`ed.
+                        type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
+                            .then(|| Symbol::intern(&field_layout.ty.to_string())),
                     }
                 })
                 .chain(upvar_fields.iter().copied())
diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs
index 66457933438..408e0bafa58 100644
--- a/compiler/stable_mir/src/mir/alloc.rs
+++ b/compiler/stable_mir/src/mir/alloc.rs
@@ -55,7 +55,7 @@ impl IndexedVal for AllocId {
 /// Utility function used to read an allocation data into a unassigned integer.
 pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
     let mut buf = [0u8; std::mem::size_of::<u128>()];
-    match MachineInfo::target_endianess() {
+    match MachineInfo::target_endianness() {
         Endian::Little => {
             bytes.read_exact(&mut buf[..bytes.len()])?;
             Ok(u128::from_le_bytes(buf))
@@ -70,7 +70,7 @@ pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
 /// Utility function used to read an allocation data into an assigned integer.
 pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> {
     let mut buf = [0u8; std::mem::size_of::<i128>()];
-    match MachineInfo::target_endianess() {
+    match MachineInfo::target_endianness() {
         Endian::Little => {
             bytes.read_exact(&mut buf[..bytes.len()])?;
             Ok(i128::from_le_bytes(buf))
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index e4a012d8c47..7c536a3e914 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -621,7 +621,7 @@ impl Rvalue {
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
                 Ok(Ty::usize_ty())
             }
-            Rvalue::NullaryOp(NullOp::UbCheck(_), _) => Ok(Ty::bool_ty()),
+            Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
             Rvalue::Aggregate(ak, ops) => match *ak {
                 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
                 AggregateKind::Tuple => Ok(Ty::new_tuple(
@@ -989,13 +989,7 @@ pub enum NullOp {
     /// Returns the offset of a field.
     OffsetOf(Vec<(VariantIdx, FieldIdx)>),
     /// cfg!(debug_assertions), but at codegen time
-    UbCheck(UbKind),
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum UbKind {
-    LanguageUb,
-    LibraryUb,
+    UbChecks,
 }
 
 impl Operand {
diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs
index 3a9011a2ffe..e00a418c540 100644
--- a/compiler/stable_mir/src/target.rs
+++ b/compiler/stable_mir/src/target.rs
@@ -14,7 +14,7 @@ impl MachineInfo {
         with(|cx| cx.target_info())
     }
 
-    pub fn target_endianess() -> Endian {
+    pub fn target_endianness() -> Endian {
         with(|cx| cx.target_info().endian)
     }
 
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 70b9e89f9ea..8f612929110 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -4,9 +4,9 @@ use crate::char::TryFromCharError;
 use crate::convert::TryFrom;
 use crate::error::Error;
 use crate::fmt;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::mem::transmute;
 use crate::str::FromStr;
+use crate::ub_checks::assert_unsafe_precondition;
 
 /// Converts a `u32` to a `char`. See [`char::from_u32`].
 #[must_use]
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index ffe059bf65c..b27d0db4619 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -4,6 +4,7 @@
 //! Hints may be compile time or runtime.
 
 use crate::intrinsics;
+use crate::ub_checks;
 
 /// Informs the compiler that the site which is calling this function is not
 /// reachable, possibly enabling further optimizations.
@@ -98,7 +99,7 @@ use crate::intrinsics;
 #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn unreachable_unchecked() -> ! {
-    intrinsics::assert_unsafe_precondition!(
+    ub_checks::assert_unsafe_precondition!(
         check_language_ub,
         "hint::unreachable_unchecked must never be reached",
         () => false
@@ -148,7 +149,7 @@ pub const unsafe fn unreachable_unchecked() -> ! {
 pub const unsafe fn assert_unchecked(cond: bool) {
     // SAFETY: The caller promised `cond` is true.
     unsafe {
-        intrinsics::assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "hint::assert_unchecked must never be called when the condition is false",
             (cond: bool = cond) => cond,
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 613d0ab212a..dec31548fc8 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -66,6 +66,8 @@
 use crate::marker::DiscriminantKind;
 use crate::marker::Tuple;
 use crate::mem::align_of;
+use crate::ptr;
+use crate::ub_checks;
 
 pub mod mir;
 pub mod simd;
@@ -1163,14 +1165,6 @@ extern "rust-intrinsic" {
     /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
     /// unsafe**. `transmute` should be the absolute last resort.
     ///
-    /// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub],
-    /// unless the pointer was originally created *from* an integer.
-    /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling],
-    /// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.)
-    /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
-    /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the
-    /// Rust memory model and should be avoided. See below for alternatives.)
-    ///
     /// Because `transmute` is a by-value operation, alignment of the *transmuted values
     /// themselves* is not a concern. As with any other function, the compiler already ensures
     /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point
@@ -1181,6 +1175,39 @@ extern "rust-intrinsic" {
     ///
     /// [ub]: ../../reference/behavior-considered-undefined.html
     ///
+    /// # Transmutation between pointers and integers
+    ///
+    /// Special care has to be taken when transmuting between pointers and integers, e.g.
+    /// transmuting between `*const ()` and `usize`.
+    ///
+    /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless
+    /// the pointer was originally created *from* an integer. (That includes this function
+    /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling],
+    /// but also semantically-equivalent conversions such as punning through `repr(C)` union
+    /// fields.) Any attempt to use the resulting value for integer operations will abort
+    /// const-evaluation. (And even outside `const`, such transmutation is touching on many
+    /// unspecified aspects of the Rust memory model and should be avoided. See below for
+    /// alternatives.)
+    ///
+    /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not*
+    /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed
+    /// this way is currently considered undefined behavior.
+    ///
+    /// All this also applies when the integer is nested inside an array, tuple, struct, or enum.
+    /// However, `MaybeUninit<usize>` is not considered an integer type for the purpose of this
+    /// section. Transmuting `*const ()` to `MaybeUninit<usize>` is fine---but then calling
+    /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute
+    /// and thus runs into the issues discussed above.
+    ///
+    /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a
+    /// lossless process. If you want to round-trip a pointer through an integer in a way that you
+    /// can get back the original pointer, you need to use `as` casts, or replace the integer type
+    /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to
+    /// store data of arbitrary type, also use `MaybeUninit<T>` (that will also handle uninitialized
+    /// memory due to padding). If you specifically need to store something that is "either an
+    /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without
+    /// any loss (via `as` casts or via `transmute`).
+    ///
     /// # Examples
     ///
     /// There are a few things that `transmute` is really useful for.
@@ -2638,38 +2665,43 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
     false
 }
 
-/// Returns whether we should check for library UB. This evaluate to the value of `cfg!(debug_assertions)`
-/// during monomorphization.
+/// Non-overlapping *typed* swap of a single value.
 ///
-/// This intrinsic is evaluated after monomorphization, and therefore branching on this value can
-/// be used to implement debug assertions that are included in the precompiled standard library,
-/// but can be optimized out by builds that monomorphize the standard library code with debug
-/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
+/// The codegen backends will replace this with a better implementation when
+/// `T` is a simple type that can be loaded and stored as an immediate.
 ///
-/// We have separate intrinsics for library UB and language UB because checkers like the const-eval
-/// interpreter and Miri already implement checks for language UB. Since such checkers do not know
-/// about library preconditions, checks guarded by this intrinsic let them find more UB.
-#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
-#[unstable(feature = "core_intrinsics", issue = "none")]
-#[inline(always)]
-#[rustc_intrinsic]
-pub(crate) const fn check_library_ub() -> bool {
-    cfg!(debug_assertions)
-}
-
-/// Returns whether we should check for language UB. This evaluate to the value of `cfg!(debug_assertions)`
-/// during monomorphization.
+/// The stabilized form of this intrinsic is [`crate::mem::swap`].
 ///
-/// Since checks implemented at the source level must come strictly before the operation that
-/// executes UB, if we enabled language UB checks in const-eval/Miri we would miss out on the
-/// interpreter's improved diagnostics for the cases that our source-level checks catch.
+/// # Safety
 ///
-/// See `check_library_ub` for more information.
-#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
+/// `x` and `y` are readable and writable as `T`, and non-overlapping.
+#[rustc_nounwind]
+#[inline]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+// This has fallback `const fn` MIR, so shouldn't need stability, see #122652
+#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")]
+pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
+    // SAFETY: The caller provided single non-overlapping items behind
+    // pointers, so swapping them with `count: 1` is fine.
+    unsafe { ptr::swap_nonoverlapping(x, y, 1) };
+}
+
+/// Returns whether we should perform some UB-checking at runtime. This evaluate to the value of
+/// `cfg!(debug_assertions)` during monomorphization.
+///
+/// This intrinsic is evaluated after monomorphization, which is relevant when mixing crates
+/// compiled with and without debug_assertions. The common case here is a user program built with
+/// debug_assertions linked against the distributed sysroot which is built without debug_assertions.
+/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with
+/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(debug_assertions)` means that
+/// assertions are enabled whenever the *user crate* has debug assertions enabled. However if the
+/// user has debug assertions disabled, the checks will still get optimized out. This intrinsic is
+/// primarily used by [`ub_checks::assert_unsafe_precondition`].
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[inline(always)]
-#[rustc_intrinsic]
-pub(crate) const fn check_language_ub() -> bool {
+#[cfg_attr(not(bootstrap), rustc_intrinsic)] // just make it a regular fn in bootstrap
+pub(crate) const fn ub_checks() -> bool {
     cfg!(debug_assertions)
 }
 
@@ -2733,132 +2765,6 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
 // (`transmute` also falls into this category, but it cannot be wrapped due to the
 // check that `T` and `U` have the same size.)
 
-/// Check that the preconditions of an unsafe function are followed. The check is enabled at
-/// runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri
-/// checks implemented with this macro for language UB are always ignored.
-///
-/// This macro should be called as
-/// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
-/// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all
-/// those arguments are passed to a function with the body `check_expr`.
-/// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB
-/// according to the Rust Abstract Machine. Pick `check_library_ub` when this is guarding a violation
-/// of a documented library precondition that does not *immediately* lead to language UB.
-///
-/// If `check_library_ub` is used but the check is actually guarding language UB, the check will
-/// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
-/// diagnostic, but our ability to detect UB is unchanged.
-/// But if `check_language_ub` is used when the check is actually for library UB, the check is
-/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
-/// library UB, the backtrace Miri reports may be far removed from original cause.
-///
-/// These checks are behind a condition which is evaluated at codegen time, not expansion time like
-/// [`debug_assert`]. This means that a standard library built with optimizations and debug
-/// assertions disabled will have these checks optimized out of its monomorphizations, but if a
-/// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
-/// this macro, that monomorphization will contain the check.
-///
-/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
-/// implementation to mitigate their compile-time overhead. Calls to this macro always expand to
-/// this structure:
-/// ```ignore (pseudocode)
-/// if ::core::intrinsics::check_language_ub() {
-///     precondition_check(args)
-/// }
-/// ```
-/// where `precondition_check` is monomorphic with the attributes `#[rustc_nounwind]`, `#[inline]` and
-/// `#[rustc_no_mir_inline]`. This combination of attributes ensures that the actual check logic is
-/// compiled only once and generates a minimal amount of IR because the check cannot be inlined in
-/// MIR, but *can* be inlined and fully optimized by a codegen backend.
-///
-/// Callers should avoid introducing any other `let` bindings or any code outside this macro in
-/// order to call it. Since the precompiled standard library is built with full debuginfo and these
-/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
-/// debuginfo to have a measurable compile-time impact on debug builds.
-#[allow_internal_unstable(ub_checks)] // permit this to be called in stably-const fn
-macro_rules! assert_unsafe_precondition {
-    ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
-        {
-            // This check is inlineable, but not by the MIR inliner.
-            // The reason for this is that the MIR inliner is in an exceptionally bad position
-            // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
-            // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
-            // would be bad for compile times.
-            //
-            // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
-            // inlining the check. If it's `true`, it can inline it and get significantly better performance.
-            #[rustc_no_mir_inline]
-            #[inline]
-            #[rustc_nounwind]
-            #[rustc_const_unstable(feature = "ub_checks", issue = "none")]
-            const fn precondition_check($($name:$ty),*) {
-                if !$e {
-                    ::core::panicking::panic_nounwind(
-                        concat!("unsafe precondition(s) violated: ", $message)
-                    );
-                }
-            }
-
-            if ::core::intrinsics::$kind() {
-                precondition_check($($arg,)*);
-            }
-        }
-    };
-}
-pub(crate) use assert_unsafe_precondition;
-
-/// Checks whether `ptr` is properly aligned with respect to
-/// `align_of::<T>()`.
-///
-/// In `const` this is approximate and can fail spuriously. It is primarily intended
-/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
-/// check is anyway not executed in `const`.
-#[inline]
-pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
-    !ptr.is_null() && ptr.is_aligned_to(align)
-}
-
-#[inline]
-pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
-    let max_len = if size == 0 { usize::MAX } else { isize::MAX as usize / size };
-    len <= max_len
-}
-
-/// Checks whether the regions of memory starting at `src` and `dst` of size
-/// `count * size` do *not* overlap.
-///
-/// Note that in const-eval this function just returns `true` and therefore must
-/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
-#[inline]
-pub(crate) const fn is_nonoverlapping(
-    src: *const (),
-    dst: *const (),
-    size: usize,
-    count: usize,
-) -> bool {
-    #[inline]
-    fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
-        let src_usize = src.addr();
-        let dst_usize = dst.addr();
-        let Some(size) = size.checked_mul(count) else {
-            crate::panicking::panic_nounwind(
-                "is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
-            )
-        };
-        let diff = src_usize.abs_diff(dst_usize);
-        // If the absolute distance between the ptrs is at least as big as the size of the buffer,
-        // they do not overlap.
-        diff >= size
-    }
-
-    #[inline]
-    const fn comptime(_: *const (), _: *const (), _: usize, _: usize) -> bool {
-        true
-    }
-
-    const_eval_select((src, dst, size, count), comptime, runtime)
-}
-
 /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
 /// and destination must *not* overlap.
 ///
@@ -2957,7 +2863,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
         pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    assert_unsafe_precondition!(
+    ub_checks::assert_unsafe_precondition!(
         check_language_ub,
         "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
         and the specified memory ranges do not overlap",
@@ -2968,9 +2874,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
             align: usize = align_of::<T>(),
             count: usize = count,
         ) =>
-        is_aligned_and_not_null(src, align)
-            && is_aligned_and_not_null(dst, align)
-            && is_nonoverlapping(src, dst, size, count)
+        ub_checks::is_aligned_and_not_null(src, align)
+            && ub_checks::is_aligned_and_not_null(dst, align)
+            && ub_checks::is_nonoverlapping(src, dst, size, count)
     );
 
     // SAFETY: the safety contract for `copy_nonoverlapping` must be
@@ -3061,7 +2967,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
 
     // SAFETY: the safety contract for `copy` must be upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
             and the specified memory ranges do not overlap",
@@ -3070,8 +2976,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
                 dst: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
             ) =>
-            is_aligned_and_not_null(src, align)
-                && is_aligned_and_not_null(dst, align)
+            ub_checks::is_aligned_and_not_null(src, align)
+                && ub_checks::is_aligned_and_not_null(dst, align)
         );
         copy(src, dst, count)
     }
@@ -3142,13 +3048,13 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 
     // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::write_bytes requires that the destination pointer is aligned and non-null",
             (
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         write_bytes(dst, val, count)
     }
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index b69f4f853b9..427a95f4665 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -470,7 +470,7 @@ extern "rust-intrinsic" {
     /// No matter whether the output is an array or an unsigned integer, it is treated as a single
     /// contiguous list of bits. The bitmask is always packed on the least-significant side of the
     /// output, and padded with 0s in the most-significant bits. The order of the bits depends on
-    /// endianess:
+    /// endianness:
     ///
     /// * On little endian, the least significant bit corresponds to the first vector element.
     /// * On big endian, the least significant bit corresponds to the last vector element.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 2718dd11473..f0448a98981 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -170,6 +170,8 @@
 #![feature(const_try)]
 #![feature(const_type_id)]
 #![feature(const_type_name)]
+#![feature(const_typed_swap)]
+#![feature(const_ub_checks)]
 #![feature(const_unicode_case_lookup)]
 #![feature(const_unsafecell_get_mut)]
 #![feature(const_waker)]
@@ -189,7 +191,6 @@
 #![feature(ptr_metadata)]
 #![feature(set_ptr_value)]
 #![feature(slice_ptr_get)]
-#![feature(slice_split_at_unchecked)]
 #![feature(split_at_checked)]
 #![feature(str_internals)]
 #![feature(str_split_inclusive_remainder)]
@@ -366,6 +367,7 @@ pub mod hint;
 pub mod intrinsics;
 pub mod mem;
 pub mod ptr;
+mod ub_checks;
 
 /* Core language traits */
 
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index d1dc6720271..75d42edbaa0 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -726,63 +726,9 @@ pub unsafe fn uninitialized<T>() -> T {
 #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
 #[rustc_diagnostic_item = "mem_swap"]
 pub const fn swap<T>(x: &mut T, y: &mut T) {
-    // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
-    // reinterpretation of values as (chunkable) byte arrays, and the loop in the
-    // block optimization in `swap_slice` is hard to rewrite back
-    // into the (unoptimized) direct swapping implementation, so we disable it.
-    #[cfg(not(any(target_arch = "spirv")))]
-    {
-        // For types that are larger multiples of their alignment, the simple way
-        // tends to copy the whole thing to stack rather than doing it one part
-        // at a time, so instead treat them as one-element slices and piggy-back
-        // the slice optimizations that will split up the swaps.
-        if const { size_of::<T>() / align_of::<T>() > 2 } {
-            // SAFETY: exclusive references always point to one non-overlapping
-            // element and are non-null and properly aligned.
-            return unsafe { ptr::swap_nonoverlapping(x, y, 1) };
-        }
-    }
-
-    // If a scalar consists of just a small number of alignment units, let
-    // the codegen just swap those pieces directly, as it's likely just a
-    // few instructions and anything else is probably overcomplicated.
-    //
-    // Most importantly, this covers primitives and simd types that tend to
-    // have size=align where doing anything else can be a pessimization.
-    // (This will also be used for ZSTs, though any solution works for them.)
-    swap_simple(x, y);
-}
-
-/// Same as [`swap`] semantically, but always uses the simple implementation.
-///
-/// Used elsewhere in `mem` and `ptr` at the bottom layer of calls.
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-#[inline]
-pub(crate) const fn swap_simple<T>(x: &mut T, y: &mut T) {
-    // We arrange for this to typically be called with small types,
-    // so this reads-and-writes approach is actually better than using
-    // copy_nonoverlapping as it easily puts things in LLVM registers
-    // directly and doesn't end up inlining allocas.
-    // And LLVM actually optimizes it to 3×memcpy if called with
-    // a type larger than it's willing to keep in a register.
-    // Having typed reads and writes in MIR here is also good as
-    // it lets Miri and CTFE understand them better, including things
-    // like enforcing type validity for them.
-    // Importantly, read+copy_nonoverlapping+write introduces confusing
-    // asymmetry to the behaviour where one value went through read+write
-    // whereas the other was copied over by the intrinsic (see #94371).
-    // Furthermore, using only read+write here benefits limited backends
-    // such as SPIR-V that work on an underlying *typed* view of memory,
-    // and thus have trouble with Rust's untyped memory operations.
-
-    // SAFETY: exclusive references are always valid to read/write,
-    // including being aligned, and nothing here panics so it's drop-safe.
-    unsafe {
-        let a = ptr::read(x);
-        let b = ptr::read(y);
-        ptr::write(x, b);
-        ptr::write(y, a);
-    }
+    // SAFETY: `&mut` guarantees these are typed readable and writable
+    // as well as non-overlapping.
+    unsafe { intrinsics::typed_swap(x, y) }
 }
 
 /// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index a8f637280df..c65ffbb98f2 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -9,6 +9,7 @@ use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::ptr;
 use crate::str::FromStr;
+use crate::ub_checks;
 
 use super::from_str_radix;
 use super::{IntErrorKind, ParseIntError};
@@ -369,7 +370,7 @@ where
             None => {
                 // SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable.
                 unsafe {
-                    intrinsics::assert_unsafe_precondition!(
+                    ub_checks::assert_unsafe_precondition!(
                         check_language_ub,
                         "NonZero::new_unchecked requires the argument to be non-zero",
                         () => false,
@@ -409,7 +410,7 @@ where
             None => {
                 // SAFETY: The caller guarantees that `n` references a value that is non-zero, so this is unreachable.
                 unsafe {
-                    intrinsics::assert_unsafe_precondition!(
+                    ub_checks::assert_unsafe_precondition!(
                         check_library_ub,
                         "NonZero::from_mut_unchecked requires the argument to dereference as non-zero",
                         () => false,
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index b28d88fa5bf..65bda9177c7 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -1,6 +1,7 @@
-use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
+use crate::intrinsics::{unchecked_add, unchecked_sub};
 use crate::iter::{FusedIterator, TrustedLen};
 use crate::num::NonZero;
+use crate::ub_checks;
 
 /// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
 ///
@@ -19,7 +20,7 @@ impl IndexRange {
     /// - `start <= end`
     #[inline]
     pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_library_ub,
             "IndexRange::new_unchecked requires `start <= end`",
             (start: usize = start, end: usize = end) => start <= end,
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index c77e9675a6a..40326221258 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -161,11 +161,12 @@ impl fmt::Display for PanicInfo<'_> {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
         formatter.write_str("panicked at ")?;
         self.location.fmt(formatter)?;
+        formatter.write_str(":")?;
         if let Some(message) = self.message {
-            formatter.write_str(":\n")?;
+            formatter.write_str("\n")?;
             formatter.write_fmt(*message)?;
         } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
-            formatter.write_str(":\n")?;
+            formatter.write_str("\n")?;
             formatter.write_str(payload)?;
         }
         // NOTE: we cannot use downcast_ref::<String>() here
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 9e8dac88816..a8940d9cd1e 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -132,11 +132,11 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
 #[rustc_const_unstable(feature = "panic_internals", issue = "none")]
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
 pub const fn panic(expr: &'static str) -> ! {
-    // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
+    // Use Arguments::new_const instead of format_args!("{expr}") to potentially
     // reduce size overhead. The format_args! macro uses str's Display trait to
     // write expr, which calls Formatter::pad, which must accommodate string
     // truncation and padding (even though none is used here). Using
-    // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
+    // Arguments::new_const may allow the compiler to omit Formatter::pad from the
     // output binary, saving up to a few kilobytes.
     panic_fmt(fmt::Arguments::new_const(&[expr]));
 }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index a0227d9130b..d14cac9afb5 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -144,7 +144,7 @@
 //!     * e.g. [`drop`]ping the [`Future`] [^pin-drop-future]
 //!
 //! There are two possible ways to ensure the invariants required for 2. and 3. above (which
-//! apply to any address-sensitive type, not just self-referrential types) do not get broken.
+//! apply to any address-sensitive type, not just self-referential types) do not get broken.
 //!
 //! 1. Have the value detect when it is moved and update all the pointers that point to itself.
 //! 2. Guarantee that the address of the value does not change (and that memory is not re-used
@@ -170,7 +170,7 @@
 //! become viral throughout all code that interacts with the object.
 //!
 //! The second option is a viable solution to the problem for some use cases, in particular
-//! for self-referrential types. Under this model, any type that has an address sensitive state
+//! for self-referential types. Under this model, any type that has an address sensitive state
 //! would ultimately store its data in something like a [`Box<T>`], carefully manage internal
 //! access to that data to ensure no *moves* or other invalidation occurs, and finally
 //! provide a safe interface on top.
@@ -186,8 +186,8 @@
 //!
 //! Although there were other reason as well, this issue of expensive composition is the key thing
 //! that drove Rust towards adopting a different model. It is particularly a problem
-//! when one considers, for exapmle, the implications of composing together the [`Future`]s which
-//! will eventaully make up an asynchronous task (including address-sensitive `async fn` state
+//! when one considers, for example, the implications of composing together the [`Future`]s which
+//! will eventually make up an asynchronous task (including address-sensitive `async fn` state
 //! machines). It is plausible that there could be many layers of [`Future`]s composed together,
 //! including multiple layers of `async fn`s handling different parts of a task. It was deemed
 //! unacceptable to force indirection and allocation for each layer of composition in this case.
@@ -359,7 +359,7 @@
 //! Builtin types that are [`Unpin`] include all of the primitive types, like [`bool`], [`i32`],
 //! and [`f32`], references (<code>[&]T</code> and <code>[&mut] T</code>), etc., as well as many
 //! core and standard library types like [`Box<T>`], [`String`], and more.
-//! These types are marked [`Unpin`] because they do not have an ddress-sensitive state like the
+//! These types are marked [`Unpin`] because they do not have an address-sensitive state like the
 //! ones we discussed above. If they did have such a state, those parts of their interface would be
 //! unsound without being expressed through pinning, and they would then need to not
 //! implement [`Unpin`].
@@ -953,7 +953,7 @@ use crate::{
 /// discussed below.
 ///
 /// We call such a [`Pin`]-wrapped pointer a **pinning pointer** (or pinning ref, or pinning
-/// [`Box`], etc.) because its existince is the thing that is pinning the underlying pointee in
+/// [`Box`], etc.) because its existence is the thing that is pinning the underlying pointee in
 /// place: it is the metaphorical "pin" securing the data in place on the pinboard (in memory).
 ///
 /// It is important to stress that the thing in the [`Pin`] is not the value which we want to pin
@@ -962,7 +962,7 @@ use crate::{
 ///
 /// The most common set of types which require pinning related guarantees for soundness are the
 /// compiler-generated state machines that implement [`Future`] for the return value of
-/// `async fn`s. These compiler-generated [`Future`]s may contain self-referrential pointers, one
+/// `async fn`s. These compiler-generated [`Future`]s may contain self-referential pointers, one
 /// of the most common use cases for [`Pin`]. More details on this point are provided in the
 /// [`pin` module] docs, but suffice it to say they require the guarantees provided by pinning to
 /// be implemented soundly.
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index 8f44b7eb7c2..bc84fb5ccb0 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -1,7 +1,7 @@
 use crate::convert::{TryFrom, TryInto};
-#[cfg(debug_assertions)]
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::num::NonZero;
+#[cfg(debug_assertions)]
+use crate::ub_checks::assert_unsafe_precondition;
 use crate::{cmp, fmt, hash, mem, num};
 
 /// A type storing a `usize` which is a power of two, and thus
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 69c61602073..a6c00ff28d4 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -818,7 +818,7 @@ impl<T: ?Sized> *const T {
             intrinsics::const_eval_select((this, origin), comptime, runtime)
         }
 
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::sub_ptr requires `self >= origin`",
             (
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 1f0204daf72..56378b437e7 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -388,10 +388,9 @@
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
-use crate::intrinsics::{
-    self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
-};
+use crate::intrinsics;
 use crate::marker::FnPtr;
+use crate::ub_checks;
 
 use crate::mem::{self, align_of, size_of, MaybeUninit};
 
@@ -1019,7 +1018,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
         };
     }
 
-    assert_unsafe_precondition!(
+    ub_checks::assert_unsafe_precondition!(
         check_language_ub,
         "ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
         and the specified memory ranges do not overlap",
@@ -1030,9 +1029,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             align: usize = align_of::<T>(),
             count: usize = count,
         ) =>
-        is_aligned_and_not_null(x, align)
-            && is_aligned_and_not_null(y, align)
-            && is_nonoverlapping(x, y, size, count)
+        ub_checks::is_aligned_and_not_null(x, align)
+            && ub_checks::is_aligned_and_not_null(y, align)
+            && ub_checks::is_nonoverlapping(x, y, size, count)
     );
 
     // Split up the slice into small power-of-two-sized chunks that LLVM is able
@@ -1062,11 +1061,26 @@ const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, coun
     let mut i = 0;
     while i < count {
         // SAFETY: By precondition, `i` is in-bounds because it's below `n`
-        let x = unsafe { &mut *x.add(i) };
+        let x = unsafe { x.add(i) };
         // SAFETY: By precondition, `i` is in-bounds because it's below `n`
         // and it's distinct from `x` since the ranges are non-overlapping
-        let y = unsafe { &mut *y.add(i) };
-        mem::swap_simple::<MaybeUninit<T>>(x, y);
+        let y = unsafe { y.add(i) };
+
+        // If we end up here, it's because we're using a simple type -- like
+        // a small power-of-two-sized thing -- or a special type with particularly
+        // large alignment, particularly SIMD types.
+        // Thus we're fine just reading-and-writing it, as either it's small
+        // and that works well anyway or it's special and the type's author
+        // presumably wanted things to be done in the larger chunk.
+
+        // SAFETY: we're only ever given pointers that are valid to read/write,
+        // including being aligned, and nothing here panics so it's drop-safe.
+        unsafe {
+            let a: MaybeUninit<T> = read(x);
+            let b: MaybeUninit<T> = read(y);
+            write(x, b);
+            write(y, a);
+        }
 
         i += 1;
     }
@@ -1120,13 +1134,13 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
     // and cannot overlap `src` since `dst` must point to a distinct
     // allocated object.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::replace requires that the pointer argument is aligned and non-null",
             (
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         mem::replace(&mut *dst, src)
     }
@@ -1272,13 +1286,13 @@ pub const unsafe fn read<T>(src: *const T) -> T {
     // SAFETY: the caller must guarantee that `src` is valid for reads.
     unsafe {
         #[cfg(debug_assertions)] // Too expensive to always enable (for now?)
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::read requires that the pointer argument is aligned and non-null",
             (
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         crate::intrinsics::read_via_copy(src)
     }
@@ -1481,13 +1495,13 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
     // to `dst` while `src` is owned by this function.
     unsafe {
         #[cfg(debug_assertions)] // Too expensive to always enable (for now?)
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::write requires that the pointer argument is aligned and non-null",
             (
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         intrinsics::write_via_move(dst, src)
     }
@@ -1653,13 +1667,13 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
     // SAFETY: the caller must uphold the safety contract for `volatile_load`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::read_volatile requires that the pointer argument is aligned and non-null",
             (
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         intrinsics::volatile_load(src)
     }
@@ -1732,13 +1746,13 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     // SAFETY: the caller must uphold the safety contract for `volatile_store`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::write_volatile requires that the pointer argument is aligned and non-null",
             (
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         intrinsics::volatile_store(dst, src);
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 2ac42e20d43..e9488917acc 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -2,7 +2,6 @@ use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
 use crate::intrinsics;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::marker::Unsize;
 use crate::mem::{MaybeUninit, SizedTypeProperties};
 use crate::num::NonZero;
@@ -10,6 +9,7 @@ use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::ptr;
 use crate::ptr::Unique;
 use crate::slice::{self, SliceIndex};
+use crate::ub_checks::assert_unsafe_precondition;
 
 /// `*mut T` but non-zero and [covariant].
 ///
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 210118817ab..127a407dae5 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -1,10 +1,10 @@
 //! Indexing implementations for `[T]`.
 
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::intrinsics::const_eval_select;
 use crate::intrinsics::unchecked_sub;
 use crate::ops;
 use crate::ptr;
+use crate::ub_checks::assert_unsafe_precondition;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, I> ops::Index<I> for [T]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4a574bf0347..a16005abf46 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -9,7 +9,6 @@
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::fmt;
 use crate::hint;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::intrinsics::exact_div;
 use crate::mem::{self, SizedTypeProperties};
 use crate::num::NonZero;
@@ -17,6 +16,7 @@ use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
 use crate::ptr;
 use crate::simd::{self, Simd};
 use crate::slice;
+use crate::ub_checks::assert_unsafe_precondition;
 
 #[unstable(
     feature = "slice_internals",
@@ -1944,8 +1944,6 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_split_at_unchecked)]
-    ///
     /// let v = [1, 2, 3, 4, 5, 6];
     ///
     /// unsafe {
@@ -1966,7 +1964,7 @@ impl<T> [T] {
     ///     assert_eq!(right, []);
     /// }
     /// ```
-    #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+    #[stable(feature = "slice_split_at_unchecked", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")]
     #[inline]
     #[must_use]
@@ -2008,8 +2006,6 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_split_at_unchecked)]
-    ///
     /// let mut v = [1, 0, 3, 0, 5, 6];
     /// // scoped to restrict the lifetime of the borrows
     /// unsafe {
@@ -2021,7 +2017,7 @@ impl<T> [T] {
     /// }
     /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
     /// ```
-    #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+    #[stable(feature = "slice_split_at_unchecked", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
     #[inline]
     #[must_use]
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 2199614ce27..29a12f106c5 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -1,12 +1,10 @@
 //! Free functions to create `&[T]` and `&mut [T]`.
 
 use crate::array;
-use crate::intrinsics::{
-    assert_unsafe_precondition, is_aligned_and_not_null, is_valid_allocation_size,
-};
 use crate::mem::{align_of, size_of};
 use crate::ops::Range;
 use crate::ptr;
+use crate::ub_checks;
 
 /// Forms a slice from a pointer and a length.
 ///
@@ -95,7 +93,7 @@ use crate::ptr;
 pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
             (
@@ -104,8 +102,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-                is_aligned_and_not_null(data, align)
-                && is_valid_allocation_size(size, len)
+            ub_checks::is_aligned_and_not_null(data, align)
+                && ub_checks::is_valid_allocation_size(size, len)
         );
         &*ptr::slice_from_raw_parts(data, len)
     }
@@ -149,7 +147,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
             (
@@ -158,8 +156,8 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-                is_aligned_and_not_null(data, align)
-                && is_valid_allocation_size(size, len)
+            ub_checks::is_aligned_and_not_null(data, align)
+                && ub_checks::is_valid_allocation_size(size, len)
         );
         &mut *ptr::slice_from_raw_parts_mut(data, len)
     }
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index ec81fd095d5..672af752149 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -1,10 +1,10 @@
 //! Trait implementations for `str`.
 
 use crate::cmp::Ordering;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::ops;
 use crate::ptr;
 use crate::slice::SliceIndex;
+use crate::ub_checks::assert_unsafe_precondition;
 
 use super::ParseBoolError;
 
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
new file mode 100644
index 00000000000..ff6b2d30539
--- /dev/null
+++ b/library/core/src/ub_checks.rs
@@ -0,0 +1,158 @@
+//! Provides the [`assert_unsafe_precondition`] macro as well as some utility functions that cover
+//! common preconditions.
+
+use crate::intrinsics::{self, const_eval_select};
+
+/// Check that the preconditions of an unsafe function are followed. The check is enabled at
+/// runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri
+/// checks implemented with this macro for language UB are always ignored.
+///
+/// This macro should be called as
+/// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
+/// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all
+/// those arguments are passed to a function with the body `check_expr`.
+/// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB
+/// according to the Rust Abstract Machine. Pick `check_library_ub` when this is guarding a violation
+/// of a documented library precondition that does not *immediately* lead to language UB.
+///
+/// If `check_library_ub` is used but the check is actually guarding language UB, the check will
+/// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
+/// diagnostic, but our ability to detect UB is unchanged.
+/// But if `check_language_ub` is used when the check is actually for library UB, the check is
+/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
+/// library UB, the backtrace Miri reports may be far removed from original cause.
+///
+/// These checks are behind a condition which is evaluated at codegen time, not expansion time like
+/// [`debug_assert`]. This means that a standard library built with optimizations and debug
+/// assertions disabled will have these checks optimized out of its monomorphizations, but if a
+/// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
+/// this macro, that monomorphization will contain the check.
+///
+/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
+/// implementation to mitigate their compile-time overhead. Calls to this macro always expand to
+/// this structure:
+/// ```ignore (pseudocode)
+/// if ::core::intrinsics::check_language_ub() {
+///     precondition_check(args)
+/// }
+/// ```
+/// where `precondition_check` is monomorphic with the attributes `#[rustc_nounwind]`, `#[inline]` and
+/// `#[rustc_no_mir_inline]`. This combination of attributes ensures that the actual check logic is
+/// compiled only once and generates a minimal amount of IR because the check cannot be inlined in
+/// MIR, but *can* be inlined and fully optimized by a codegen backend.
+///
+/// Callers should avoid introducing any other `let` bindings or any code outside this macro in
+/// order to call it. Since the precompiled standard library is built with full debuginfo and these
+/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
+/// debuginfo to have a measurable compile-time impact on debug builds.
+#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
+macro_rules! assert_unsafe_precondition {
+    ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
+        {
+            // This check is inlineable, but not by the MIR inliner.
+            // The reason for this is that the MIR inliner is in an exceptionally bad position
+            // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
+            // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
+            // would be bad for compile times.
+            //
+            // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
+            // inlining the check. If it's `true`, it can inline it and get significantly better performance.
+            #[rustc_no_mir_inline]
+            #[inline]
+            #[rustc_nounwind]
+            #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+            const fn precondition_check($($name:$ty),*) {
+                if !$e {
+                    ::core::panicking::panic_nounwind(
+                        concat!("unsafe precondition(s) violated: ", $message)
+                    );
+                }
+            }
+
+            if ::core::ub_checks::$kind() {
+                precondition_check($($arg,)*);
+            }
+        }
+    };
+}
+pub(crate) use assert_unsafe_precondition;
+
+/// Checking library UB is always enabled when UB-checking is done
+/// (and we use a reexport so that there is no unnecessary wrapper function).
+pub(crate) use intrinsics::ub_checks as check_library_ub;
+
+/// Determines whether we should check for language UB.
+///
+/// The intention is to not do that when running in the interpreter, as that one has its own
+/// language UB checks which generally produce better errors.
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+#[inline]
+pub(crate) const fn check_language_ub() -> bool {
+    #[inline]
+    fn runtime() -> bool {
+        // Disable UB checks in Miri.
+        !cfg!(miri)
+    }
+
+    #[inline]
+    const fn comptime() -> bool {
+        // Always disable UB checks.
+        false
+    }
+
+    // Only used for UB checks so we may const_eval_select.
+    intrinsics::ub_checks() && const_eval_select((), comptime, runtime)
+}
+
+/// Checks whether `ptr` is properly aligned with respect to
+/// `align_of::<T>()`.
+///
+/// In `const` this is approximate and can fail spuriously. It is primarily intended
+/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
+/// check is anyway not executed in `const`.
+#[inline]
+pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
+    !ptr.is_null() && ptr.is_aligned_to(align)
+}
+
+#[inline]
+pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
+    let max_len = if size == 0 { usize::MAX } else { isize::MAX as usize / size };
+    len <= max_len
+}
+
+/// Checks whether the regions of memory starting at `src` and `dst` of size
+/// `count * size` do *not* overlap.
+///
+/// Note that in const-eval this function just returns `true` and therefore must
+/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
+#[inline]
+pub(crate) const fn is_nonoverlapping(
+    src: *const (),
+    dst: *const (),
+    size: usize,
+    count: usize,
+) -> bool {
+    #[inline]
+    fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
+        let src_usize = src.addr();
+        let dst_usize = dst.addr();
+        let Some(size) = size.checked_mul(count) else {
+            crate::panicking::panic_nounwind(
+                "is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
+            )
+        };
+        let diff = src_usize.abs_diff(dst_usize);
+        // If the absolute distance between the ptrs is at least as big as the size of the buffer,
+        // they do not overlap.
+        diff >= size
+    }
+
+    #[inline]
+    const fn comptime(_: *const (), _: *const (), _: usize, _: usize) -> bool {
+        true
+    }
+
+    // This is just for safety checks so we can const_eval_select.
+    const_eval_select((src, dst, size, count), comptime, runtime)
+}
diff --git a/library/portable-simd/.github/workflows/ci.yml b/library/portable-simd/.github/workflows/ci.yml
index 90543044ea8..b292be2d6f9 100644
--- a/library/portable-simd/.github/workflows/ci.yml
+++ b/library/portable-simd/.github/workflows/ci.yml
@@ -141,6 +141,11 @@ jobs:
       - name: Test (release)
         run: cargo test --verbose --target=${{ matrix.target }} --release
 
+      - name: Generate docs
+        run: cargo doc --verbose --target=${{ matrix.target }}
+        env:
+          RUSTDOCFLAGS: -Dwarnings
+
   wasm-tests:
     name: "wasm (firefox, ${{ matrix.name }})"
     runs-on: ubuntu-latest
diff --git a/library/portable-simd/Cargo.lock b/library/portable-simd/Cargo.lock
index 46312c09657..1584c704fb2 100644
--- a/library/portable-simd/Cargo.lock
+++ b/library/portable-simd/Cargo.lock
@@ -177,6 +177,9 @@ name = "std_float"
 version = "0.1.0"
 dependencies = [
  "core_simd",
+ "test_helpers",
+ "wasm-bindgen",
+ "wasm-bindgen-test",
 ]
 
 [[package]]
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index a25723e11ce..7a161b7e01d 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -13,11 +13,12 @@
     simd_ffi,
     staged_api,
     strict_provenance,
+    prelude_import,
     ptr_metadata
 )]
 #![cfg_attr(
     all(
-        any(target_arch = "aarch64", target_arch = "arm",),
+        any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",),
         any(
             all(target_feature = "v6", not(target_feature = "mclass")),
             all(target_feature = "mclass", target_feature = "dsp"),
@@ -33,12 +34,21 @@
     any(target_arch = "powerpc", target_arch = "powerpc64"),
     feature(stdarch_powerpc)
 )]
+#![cfg_attr(
+    all(target_arch = "x86_64", target_feature = "avx512f"),
+    feature(stdarch_x86_avx512)
+)]
 #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
 #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
+#![doc(test(attr(deny(warnings))))]
 #![allow(internal_features)]
 #![unstable(feature = "portable_simd", issue = "86656")]
 //! Portable SIMD module.
 
+#[prelude_import]
+#[allow(unused_imports)]
+use core::prelude::v1::*;
+
 #[path = "mod.rs"]
 mod core_simd;
 pub use self::core_simd::simd;
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index e480c25a51e..e6e27c76a5e 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -34,6 +34,7 @@ mod sealed {
         fn eq(self, other: Self) -> bool;
 
         fn to_usize(self) -> usize;
+        fn max_unsigned() -> u64;
 
         type Unsigned: SimdElement;
 
@@ -78,6 +79,11 @@ macro_rules! impl_element {
                 self as usize
             }
 
+            #[inline]
+            fn max_unsigned() -> u64 {
+                <$unsigned>::MAX as u64
+            }
+
             type Unsigned = $unsigned;
 
             const TRUE: Self = -1;
diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
index ae9ff6894b0..8a1079042f0 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
@@ -16,7 +16,10 @@ where
     #[inline]
     pub fn swizzle_dyn(self, idxs: Simd<u8, N>) -> Self {
         #![allow(unused_imports, unused_unsafe)]
-        #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
+        #[cfg(all(
+            any(target_arch = "aarch64", target_arch = "arm64ec"),
+            target_endian = "little"
+        ))]
         use core::arch::aarch64::{uint8x8_t, vqtbl1q_u8, vtbl1_u8};
         #[cfg(all(
             target_arch = "arm",
@@ -37,6 +40,7 @@ where
                 #[cfg(all(
                     any(
                         target_arch = "aarch64",
+                        target_arch = "arm64ec",
                         all(target_arch = "arm", target_feature = "v7")
                     ),
                     target_feature = "neon",
@@ -48,7 +52,7 @@ where
                 #[cfg(target_feature = "simd128")]
                 16 => transize(wasm::i8x16_swizzle, self, idxs),
                 #[cfg(all(
-                    target_arch = "aarch64",
+                    any(target_arch = "aarch64", target_arch = "arm64ec"),
                     target_feature = "neon",
                     target_endian = "little"
                 ))]
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index 9e97a3161bb..6c8205b112c 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -1,5 +1,6 @@
 use crate::simd::{
     cmp::SimdPartialOrd,
+    num::SimdUint,
     ptr::{SimdConstPtr, SimdMutPtr},
     LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle,
 };
@@ -262,6 +263,7 @@ where
     /// # Panics
     ///
     /// Panics if the slice's length is less than the vector's `Simd::N`.
+    /// Use `load_or_default` for an alternative that does not panic.
     ///
     /// # Example
     ///
@@ -315,6 +317,143 @@ where
         unsafe { self.store(slice.as_mut_ptr().cast()) }
     }
 
+    /// Reads contiguous elements from `slice`. Elements are read so long as they're in-bounds for
+    /// the `slice`. Otherwise, the default value for the element type is returned.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::Simd;
+    /// let vec: Vec<i32> = vec![10, 11];
+    ///
+    /// let result = Simd::<i32, 4>::load_or_default(&vec);
+    /// assert_eq!(result, Simd::from_array([10, 11, 0, 0]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_or_default(slice: &[T]) -> Self
+    where
+        T: Default,
+    {
+        Self::load_or(slice, Default::default())
+    }
+
+    /// Reads contiguous elements from `slice`. Elements are read so long as they're in-bounds for
+    /// the `slice`. Otherwise, the corresponding value from `or` is passed through.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::Simd;
+    /// let vec: Vec<i32> = vec![10, 11];
+    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::load_or(&vec, or);
+    /// assert_eq!(result, Simd::from_array([10, 11, -3, -2]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_or(slice: &[T], or: Self) -> Self {
+        Self::load_select(slice, Mask::splat(true), or)
+    }
+
+    /// Reads contiguous elements from `slice`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled or out of bounds for the slice, that memory location
+    /// is not accessed and the corresponding value from `or` is passed through.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let enable = Mask::from_array([true, true, false, true]);
+    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::load_select(&vec, enable, or);
+    /// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_select_or_default(slice: &[T], enable: Mask<<T as SimdElement>::Mask, N>) -> Self
+    where
+        T: Default,
+    {
+        Self::load_select(slice, enable, Default::default())
+    }
+
+    /// Reads contiguous elements from `slice`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled or out of bounds for the slice, that memory location
+    /// is not accessed and the corresponding value from `or` is passed through.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let enable = Mask::from_array([true, true, false, true]);
+    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::load_select(&vec, enable, or);
+    /// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_select(
+        slice: &[T],
+        mut enable: Mask<<T as SimdElement>::Mask, N>,
+        or: Self,
+    ) -> Self {
+        enable &= mask_up_to(slice.len());
+        // SAFETY: We performed the bounds check by updating the mask. &[T] is properly aligned to
+        // the element.
+        unsafe { Self::load_select_ptr(slice.as_ptr(), enable, or) }
+    }
+
+    /// Reads contiguous elements from `slice`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled, that memory location is not accessed and the corresponding
+    /// value from `or` is passed through.
+    #[must_use]
+    #[inline]
+    pub unsafe fn load_select_unchecked(
+        slice: &[T],
+        enable: Mask<<T as SimdElement>::Mask, N>,
+        or: Self,
+    ) -> Self {
+        let ptr = slice.as_ptr();
+        // SAFETY: The safety of reading elements from `slice` is ensured by the caller.
+        unsafe { Self::load_select_ptr(ptr, enable, or) }
+    }
+
+    /// Reads contiguous elements starting at `ptr`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled, that memory location is not accessed and the corresponding
+    /// value from `or` is passed through.
+    #[must_use]
+    #[inline]
+    pub unsafe fn load_select_ptr(
+        ptr: *const T,
+        enable: Mask<<T as SimdElement>::Mask, N>,
+        or: Self,
+    ) -> Self {
+        // SAFETY: The safety of reading elements through `ptr` is ensured by the caller.
+        unsafe { core::intrinsics::simd::simd_masked_load(enable.to_int(), ptr, or) }
+    }
+
     /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
     /// If an index is out-of-bounds, the element is instead selected from the `or` vector.
     ///
@@ -493,6 +632,77 @@ where
         unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_int()) }
     }
 
+    /// Conditionally write contiguous elements to `slice`. The `enable` mask controls
+    /// which elements are written, as long as they're in-bounds of the `slice`.
+    /// If the element is disabled or out of bounds, no memory access to that location
+    /// is made.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let mut arr = [0i32; 4];
+    /// let write = Simd::from_array([-5, -4, -3, -2]);
+    /// let enable = Mask::from_array([false, true, true, true]);
+    ///
+    /// write.store_select(&mut arr[..3], enable);
+    /// assert_eq!(arr, [0, -4, -3, 0]);
+    /// ```
+    #[inline]
+    pub fn store_select(self, slice: &mut [T], mut enable: Mask<<T as SimdElement>::Mask, N>) {
+        enable &= mask_up_to(slice.len());
+        // SAFETY: We performed the bounds check by updating the mask. &[T] is properly aligned to
+        // the element.
+        unsafe { self.store_select_ptr(slice.as_mut_ptr(), enable) }
+    }
+
+    /// Conditionally write contiguous elements to `slice`. The `enable` mask controls
+    /// which elements are written.
+    ///
+    /// # Safety
+    ///
+    /// Every enabled element must be in bounds for the `slice`.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let mut arr = [0i32; 4];
+    /// let write = Simd::from_array([-5, -4, -3, -2]);
+    /// let enable = Mask::from_array([false, true, true, true]);
+    ///
+    /// unsafe { write.store_select_unchecked(&mut arr, enable) };
+    /// assert_eq!(arr, [0, -4, -3, -2]);
+    /// ```
+    #[inline]
+    pub unsafe fn store_select_unchecked(
+        self,
+        slice: &mut [T],
+        enable: Mask<<T as SimdElement>::Mask, N>,
+    ) {
+        let ptr = slice.as_mut_ptr();
+        // SAFETY: The safety of writing elements in `slice` is ensured by the caller.
+        unsafe { self.store_select_ptr(ptr, enable) }
+    }
+
+    /// Conditionally write contiguous elements starting from `ptr`.
+    /// The `enable` mask controls which elements are written.
+    /// When disabled, the memory location corresponding to that element is not accessed.
+    ///
+    /// # Safety
+    ///
+    /// Memory addresses for element are calculated [`pointer::wrapping_offset`] and
+    /// each enabled element must satisfy the same conditions as [`core::ptr::write`].
+    #[inline]
+    pub unsafe fn store_select_ptr(self, ptr: *mut T, enable: Mask<<T as SimdElement>::Mask, N>) {
+        // SAFETY: The safety of writing elements through `ptr` is ensured by the caller.
+        unsafe { core::intrinsics::simd::simd_masked_store(enable.to_int(), ptr, self) }
+    }
+
     /// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
     /// If an index is out-of-bounds, the write is suppressed without panicking.
     /// If two elements in the scattered vector would write to the same index
@@ -980,3 +1190,37 @@ where
 {
     type Mask = isize;
 }
+
+#[inline]
+fn lane_indices<const N: usize>() -> Simd<usize, N>
+where
+    LaneCount<N>: SupportedLaneCount,
+{
+    let mut index = [0; N];
+    for i in 0..N {
+        index[i] = i;
+    }
+    Simd::from_array(index)
+}
+
+#[inline]
+fn mask_up_to<M, const N: usize>(len: usize) -> Mask<M, N>
+where
+    LaneCount<N>: SupportedLaneCount,
+    M: MaskElement,
+{
+    let index = lane_indices::<N>();
+    let max_value: u64 = M::max_unsigned();
+    macro_rules! case {
+        ($ty:ty) => {
+            if N < <$ty>::MAX as usize && max_value as $ty as u64 == max_value {
+                return index.cast().simd_lt(Simd::splat(len.min(N) as $ty)).cast();
+            }
+        };
+    }
+    case!(u8);
+    case!(u16);
+    case!(u32);
+    case!(u64);
+    index.simd_lt(Simd::splat(len)).cast()
+}
diff --git a/library/portable-simd/crates/core_simd/src/vendor.rs b/library/portable-simd/crates/core_simd/src/vendor.rs
index 6223bedb4e1..1a34a3a8de5 100644
--- a/library/portable-simd/crates/core_simd/src/vendor.rs
+++ b/library/portable-simd/crates/core_simd/src/vendor.rs
@@ -24,7 +24,7 @@ mod x86;
 #[cfg(target_arch = "wasm32")]
 mod wasm32;
 
-#[cfg(any(target_arch = "aarch64", target_arch = "arm",))]
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",))]
 mod arm;
 
 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
diff --git a/library/portable-simd/crates/core_simd/src/vendor/arm.rs b/library/portable-simd/crates/core_simd/src/vendor/arm.rs
index ee5c6421373..f8878d11f09 100644
--- a/library/portable-simd/crates/core_simd/src/vendor/arm.rs
+++ b/library/portable-simd/crates/core_simd/src/vendor/arm.rs
@@ -4,12 +4,13 @@ use crate::simd::*;
 #[cfg(target_arch = "arm")]
 use core::arch::arm::*;
 
-#[cfg(target_arch = "aarch64")]
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))]
 use core::arch::aarch64::*;
 
 #[cfg(all(
     any(
         target_arch = "aarch64",
+        target_arch = "arm64ec",
         all(target_arch = "arm", target_feature = "v7"),
     ),
     target_endian = "little"
@@ -69,7 +70,10 @@ mod simd32 {
     from_transmute! { unsafe Simd<i8, 4> => int8x4_t }
 }
 
-#[cfg(target_arch = "aarch64")]
+#[cfg(all(
+    any(target_arch = "aarch64", target_arch = "arm64ec"),
+    target_endian = "little"
+))]
 mod aarch64 {
     use super::neon::*;
     use super::*;
diff --git a/library/portable-simd/crates/core_simd/tests/masked_load_store.rs b/library/portable-simd/crates/core_simd/tests/masked_load_store.rs
new file mode 100644
index 00000000000..3d38658e945
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/tests/masked_load_store.rs
@@ -0,0 +1,35 @@
+#![feature(portable_simd)]
+use core_simd::simd::prelude::*;
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn masked_load_store() {
+    let mut arr = [u8::MAX; 7];
+
+    u8x4::splat(0).store_select(&mut arr[5..], Mask::from_array([false, true, false, true]));
+    // write to index 8 is OOB and dropped
+    assert_eq!(arr, [255u8, 255, 255, 255, 255, 255, 0]);
+
+    u8x4::from_array([0, 1, 2, 3]).store_select(&mut arr[1..], Mask::splat(true));
+    assert_eq!(arr, [255u8, 0, 1, 2, 3, 255, 0]);
+
+    // read from index 8 is OOB and dropped
+    assert_eq!(
+        u8x4::load_or(&arr[4..], u8x4::splat(42)),
+        u8x4::from_array([3, 255, 0, 42])
+    );
+    assert_eq!(
+        u8x4::load_select(
+            &arr[4..],
+            Mask::from_array([true, false, true, true]),
+            u8x4::splat(42)
+        ),
+        u8x4::from_array([3, 42, 0, 42])
+    );
+}
diff --git a/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs
index f21a937f01c..19ffe1417c8 100644
--- a/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs
@@ -1,6 +1,6 @@
 #![feature(portable_simd)]
 use core::{fmt, ops::RangeInclusive};
-use test_helpers::{self, biteq, make_runner, prop_assert_biteq};
+use test_helpers::{biteq, make_runner, prop_assert_biteq};
 
 fn swizzle_dyn_scalar_ver<const N: usize>(values: [u8; N], idxs: [u8; N]) -> [u8; N] {
     let mut array = [0; N];
diff --git a/library/portable-simd/crates/std_float/Cargo.toml b/library/portable-simd/crates/std_float/Cargo.toml
index 84c69774cbd..0896094ee63 100644
--- a/library/portable-simd/crates/std_float/Cargo.toml
+++ b/library/portable-simd/crates/std_float/Cargo.toml
@@ -8,6 +8,13 @@ edition = "2021"
 [dependencies]
 core_simd = { path = "../core_simd", default-features = false }
 
+[dev-dependencies.test_helpers]
+path = "../test_helpers"
+
+[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
+wasm-bindgen = "0.2"
+wasm-bindgen-test = "0.3"
+
 [features]
 default = ["as_crate"]
 as_crate = []
diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs
index 4c547777fde..148aa5f9f17 100644
--- a/library/portable-simd/crates/std_float/src/lib.rs
+++ b/library/portable-simd/crates/std_float/src/lib.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "as_crate", no_std)] // We are std!
 #![cfg_attr(
     feature = "as_crate",
     feature(core_intrinsics),
@@ -44,7 +43,7 @@ use crate::sealed::Sealed;
 /// For now this trait is available to permit experimentation with SIMD float
 /// operations that may lack hardware support, such as `mul_add`.
 pub trait StdFloat: Sealed + Sized {
-    /// Fused multiply-add.  Computes `(self * a) + b` with only one rounding error,
+    /// Elementwise fused multiply-add. Computes `(self * a) + b` with only one rounding error,
     /// yielding a more accurate result than an unfused multiply-add.
     ///
     /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
@@ -57,22 +56,65 @@ pub trait StdFloat: Sealed + Sized {
         unsafe { intrinsics::simd_fma(self, a, b) }
     }
 
-    /// Produces a vector where every lane has the square root value
-    /// of the equivalently-indexed lane in `self`
+    /// Produces a vector where every element has the square root value
+    /// of the equivalently-indexed element in `self`
     #[inline]
     #[must_use = "method returns a new vector and does not mutate the original value"]
     fn sqrt(self) -> Self {
         unsafe { intrinsics::simd_fsqrt(self) }
     }
 
-    /// Returns the smallest integer greater than or equal to each lane.
+    /// Produces a vector where every element has the sine of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn sin(self) -> Self;
+
+    /// Produces a vector where every element has the cosine of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn cos(self) -> Self;
+
+    /// Produces a vector where every element has the exponential (base e) of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn exp(self) -> Self;
+
+    /// Produces a vector where every element has the exponential (base 2) of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn exp2(self) -> Self;
+
+    /// Produces a vector where every element has the natural logarithm of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn ln(self) -> Self;
+
+    /// Produces a vector where every element has the logarithm with respect to an arbitrary
+    /// in the equivalently-indexed elements in `self` and `base`.
+    #[inline]
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn log(self, base: Self) -> Self {
+        unsafe { intrinsics::simd_div(self.ln(), base.ln()) }
+    }
+
+    /// Produces a vector where every element has the base-2 logarithm of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn log2(self) -> Self;
+
+    /// Produces a vector where every element has the base-10 logarithm of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn log10(self) -> Self;
+
+    /// Returns the smallest integer greater than or equal to each element.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn ceil(self) -> Self {
         unsafe { intrinsics::simd_ceil(self) }
     }
 
-    /// Returns the largest integer value less than or equal to each lane.
+    /// Returns the largest integer value less than or equal to each element.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn floor(self) -> Self {
@@ -101,46 +143,65 @@ pub trait StdFloat: Sealed + Sized {
 impl<const N: usize> Sealed for Simd<f32, N> where LaneCount<N>: SupportedLaneCount {}
 impl<const N: usize> Sealed for Simd<f64, N> where LaneCount<N>: SupportedLaneCount {}
 
-// We can safely just use all the defaults.
-impl<const N: usize> StdFloat for Simd<f32, N>
-where
-    LaneCount<N>: SupportedLaneCount,
-{
-    /// Returns the floating point's fractional value, with its integer part removed.
-    #[must_use = "method returns a new vector and does not mutate the original value"]
-    #[inline]
-    fn fract(self) -> Self {
-        self - self.trunc()
-    }
-}
-
-impl<const N: usize> StdFloat for Simd<f64, N>
-where
-    LaneCount<N>: SupportedLaneCount,
-{
-    /// Returns the floating point's fractional value, with its integer part removed.
-    #[must_use = "method returns a new vector and does not mutate the original value"]
-    #[inline]
-    fn fract(self) -> Self {
-        self - self.trunc()
+macro_rules! impl_float {
+    {
+        $($fn:ident: $intrinsic:ident,)*
+    } => {
+        impl<const N: usize> StdFloat for Simd<f32, N>
+        where
+            LaneCount<N>: SupportedLaneCount,
+        {
+            #[inline]
+            fn fract(self) -> Self {
+                self - self.trunc()
+            }
+
+            $(
+            #[inline]
+            fn $fn(self) -> Self {
+                unsafe { intrinsics::$intrinsic(self) }
+            }
+            )*
+        }
+
+        impl<const N: usize> StdFloat for Simd<f64, N>
+        where
+            LaneCount<N>: SupportedLaneCount,
+        {
+            #[inline]
+            fn fract(self) -> Self {
+                self - self.trunc()
+            }
+
+            $(
+            #[inline]
+            fn $fn(self) -> Self {
+                // https://github.com/llvm/llvm-project/issues/83729
+                #[cfg(target_arch = "aarch64")]
+                {
+                    let mut ln = Self::splat(0f64);
+                    for i in 0..N {
+                        ln[i] = self[i].$fn()
+                    }
+                    ln
+                }
+
+                #[cfg(not(target_arch = "aarch64"))]
+                {
+                    unsafe { intrinsics::$intrinsic(self) }
+                }
+            }
+            )*
+        }
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use simd::prelude::*;
-
-    #[test]
-    fn everything_works() {
-        let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]);
-        let x2 = x + x;
-        let _xc = x.ceil();
-        let _xf = x.floor();
-        let _xr = x.round();
-        let _xt = x.trunc();
-        let _xfma = x.mul_add(x, x);
-        let _xsqrt = x.sqrt();
-        let _ = x2.abs() * x2;
-    }
+impl_float! {
+    sin: simd_fsin,
+    cos: simd_fcos,
+    exp: simd_fexp,
+    exp2: simd_fexp2,
+    ln: simd_flog,
+    log2: simd_flog2,
+    log10: simd_flog10,
 }
diff --git a/library/portable-simd/crates/std_float/tests/float.rs b/library/portable-simd/crates/std_float/tests/float.rs
new file mode 100644
index 00000000000..c66c968f8c6
--- /dev/null
+++ b/library/portable-simd/crates/std_float/tests/float.rs
@@ -0,0 +1,74 @@
+#![feature(portable_simd)]
+
+macro_rules! unary_test {
+    { $scalar:tt, $($func:tt),+ } => {
+        test_helpers::test_lanes! {
+            $(
+            fn $func<const LANES: usize>() {
+                test_helpers::test_unary_elementwise(
+                    &core_simd::simd::Simd::<$scalar, LANES>::$func,
+                    &$scalar::$func,
+                    &|_| true,
+                )
+            }
+            )*
+        }
+    }
+}
+
+macro_rules! binary_test {
+    { $scalar:tt, $($func:tt),+ } => {
+        test_helpers::test_lanes! {
+            $(
+            fn $func<const LANES: usize>() {
+                test_helpers::test_binary_elementwise(
+                    &core_simd::simd::Simd::<$scalar, LANES>::$func,
+                    &$scalar::$func,
+                    &|_, _| true,
+                )
+            }
+            )*
+        }
+    }
+}
+
+macro_rules! ternary_test {
+    { $scalar:tt, $($func:tt),+ } => {
+        test_helpers::test_lanes! {
+            $(
+            fn $func<const LANES: usize>() {
+                test_helpers::test_ternary_elementwise(
+                    &core_simd::simd::Simd::<$scalar, LANES>::$func,
+                    &$scalar::$func,
+                    &|_, _, _| true,
+                )
+            }
+            )*
+        }
+    }
+}
+
+macro_rules! impl_tests {
+    { $scalar:tt } => {
+        mod $scalar {
+            use std_float::StdFloat;
+
+            unary_test! { $scalar, sqrt, sin, cos, exp, exp2, ln, log2, log10, ceil, floor, round, trunc }
+            binary_test! { $scalar, log }
+            ternary_test! { $scalar, mul_add }
+
+            test_helpers::test_lanes! {
+                fn fract<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise_flush_subnormals(
+                        &core_simd::simd::Simd::<$scalar, LANES>::fract,
+                        &$scalar::fract,
+                        &|_| true,
+                    )
+                }
+            }
+        }
+    }
+}
+
+impl_tests! { f32 }
+impl_tests! { f64 }
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index b0bcab7994c..e6e1d32fa54 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -746,7 +746,13 @@ fn rust_panic_with_hook(
             panic_count::MustAbort::PanicInHook => {
                 // Don't try to print the message in this case
                 // - perhaps that is causing the recursive panics.
-                rtprintpanic!("thread panicked while processing panic. aborting.\n");
+                let panicinfo = PanicInfo::internal_constructor(
+                    None,     // no message
+                    location, // but we want to show the location!
+                    can_unwind,
+                    force_no_backtrace,
+                );
+                rtprintpanic!("{panicinfo}\nthread panicked while processing panic. aborting.\n");
             }
             panic_count::MustAbort::AlwaysAbort => {
                 // Unfortunately, this does not print a backtrace, because creating
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 895fcbd6b7e..d417034f5af 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -396,7 +396,7 @@ impl<T: ?Sized> Mutex<T> {
         self.poison.get()
     }
 
-    /// Clear the poisoned state from a mutex
+    /// Clear the poisoned state from a mutex.
     ///
     /// If the mutex is poisoned, it will remain poisoned until this function is called. This
     /// allows recovering from a poisoned state and marking that it has recovered. For example, if
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index f7f098c082a..d648cd08994 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -439,7 +439,7 @@ impl<T: ?Sized> RwLock<T> {
         self.poison.get()
     }
 
-    /// Clear the poisoned state from a lock
+    /// Clear the poisoned state from a lock.
     ///
     /// If the lock is poisoned, it will remain poisoned until this function is called. This allows
     /// recovering from a poisoned state and marking that it has recovered. For example, if the
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index ba53ed88f37..23aa4da14a7 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -10,14 +10,16 @@
 //! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)
 
 use r_efi::efi::{self, Guid};
+use r_efi::protocols::{device_path, device_path_to_text};
 
+use crate::ffi::OsString;
+use crate::io::{self, const_io_error};
 use crate::mem::{size_of, MaybeUninit};
-use crate::os::uefi;
+use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt};
 use crate::ptr::NonNull;
-use crate::{
-    io::{self, const_io_error},
-    os::uefi::env::boot_services,
-};
+use crate::slice;
+use crate::sync::atomic::{AtomicPtr, Ordering};
+use crate::sys_common::wstr::WStrUnits;
 
 const BOOT_SERVICES_UNAVAILABLE: io::Error =
     const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
@@ -142,9 +144,74 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result
 
 /// Get the Protocol for current system handle.
 /// Note: Some protocols need to be manually freed. It is the callers responsibility to do so.
-pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> {
-    let system_handle = uefi::env::try_image_handle()?;
-    open_protocol(system_handle, protocol_guid).ok()
+pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> io::Result<NonNull<T>> {
+    let system_handle = uefi::env::try_image_handle().ok_or(io::const_io_error!(
+        io::ErrorKind::NotFound,
+        "Protocol not found in Image handle"
+    ))?;
+    open_protocol(system_handle, protocol_guid)
+}
+
+pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::Result<OsString> {
+    fn path_to_text(
+        protocol: NonNull<device_path_to_text::Protocol>,
+        path: NonNull<device_path::Protocol>,
+    ) -> io::Result<OsString> {
+        let path_ptr: *mut r_efi::efi::Char16 = unsafe {
+            ((*protocol.as_ptr()).convert_device_path_to_text)(
+                path.as_ptr(),
+                // DisplayOnly
+                r_efi::efi::Boolean::FALSE,
+                // AllowShortcuts
+                r_efi::efi::Boolean::FALSE,
+            )
+        };
+
+        // SAFETY: `convert_device_path_to_text` returns a pointer to a null-terminated UTF-16
+        // string, and that string cannot be deallocated prior to dropping the `WStrUnits`, so
+        // it's safe for `WStrUnits` to use.
+        let path_len = unsafe {
+            WStrUnits::new(path_ptr)
+                .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?
+                .count()
+        };
+
+        let path = OsString::from_wide(unsafe { slice::from_raw_parts(path_ptr.cast(), path_len) });
+
+        if let Some(boot_services) = crate::os::uefi::env::boot_services() {
+            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
+            unsafe {
+                ((*boot_services.as_ptr()).free_pool)(path_ptr.cast());
+            }
+        }
+
+        Ok(path)
+    }
+
+    static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+        AtomicPtr::new(crate::ptr::null_mut());
+
+    if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
+        if let Ok(protocol) = open_protocol::<device_path_to_text::Protocol>(
+            handle,
+            device_path_to_text::PROTOCOL_GUID,
+        ) {
+            return path_to_text(protocol, path);
+        }
+    }
+
+    let device_path_to_text_handles = locate_handles(device_path_to_text::PROTOCOL_GUID)?;
+    for handle in device_path_to_text_handles {
+        if let Ok(protocol) = open_protocol::<device_path_to_text::Protocol>(
+            handle,
+            device_path_to_text::PROTOCOL_GUID,
+        ) {
+            LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
+            return path_to_text(protocol, path);
+        }
+    }
+
+    Err(io::const_io_error!(io::ErrorKind::NotFound, "No device path to text protocol found"))
 }
 
 /// Get RuntimeServices
diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs
index e6693db68e6..58838c5876e 100644
--- a/library/std/src/sys/pal/uefi/os.rs
+++ b/library/std/src/sys/pal/uefi/os.rs
@@ -1,4 +1,4 @@
-use super::{unsupported, RawOsError};
+use super::{helpers, unsupported, RawOsError};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::fmt;
@@ -7,6 +7,7 @@ use crate::marker::PhantomData;
 use crate::os::uefi;
 use crate::path::{self, PathBuf};
 use crate::ptr::NonNull;
+use r_efi::efi::protocols::{device_path, loaded_image_device_path};
 use r_efi::efi::Status;
 
 pub fn errno() -> RawOsError {
@@ -164,7 +165,10 @@ impl fmt::Display for JoinPathsError {
 impl StdError for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
-    unsupported()
+    let protocol = helpers::image_handle_protocol::<device_path::Protocol>(
+        loaded_image_device_path::PROTOCOL_GUID,
+    )?;
+    helpers::device_path_to_text(protocol).map(PathBuf::from)
 }
 
 pub struct Env(!);
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 25bb5938b4c..51d31a00afe 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(staged_api)]
 #![feature(c_unwind)]
 #![feature(strict_provenance)]
+#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 #![cfg_attr(
     all(target_family = "wasm", not(target_os = "emscripten")),
diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs
index b06671bcb83..f4ffac1ba16 100644
--- a/library/unwind/src/wasm.rs
+++ b/library/unwind/src/wasm.rs
@@ -59,7 +59,10 @@ pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwi
             wasm_throw(0, exception.cast())
         } else {
             let _ = exception;
-            core::arch::wasm32::unreachable()
+            #[cfg(target_arch = "wasm32")]
+            core::arch::wasm32::unreachable();
+            #[cfg(target_arch = "wasm64")]
+            core::arch::wasm64::unreachable();
         }
     }
 }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index c6eb7be08cd..211921715b0 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -20,9 +20,9 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
 use rustc_target::spec::{Target, TargetTriple};
-use tempfile::Builder as TempFileBuilder;
 
 use std::env;
+use std::fs::File;
 use std::io::{self, Write};
 use std::panic;
 use std::path::{Path, PathBuf};
@@ -31,6 +31,8 @@ use std::str;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Mutex};
 
+use tempfile::{Builder as TempFileBuilder, TempDir};
+
 use crate::clean::{types::AttributesExt, Attributes};
 use crate::config::Options as RustdocOptions;
 use crate::html::markdown::{self, ErrorCodes, Ignore, LangString};
@@ -48,7 +50,55 @@ pub(crate) struct GlobalTestOptions {
     pub(crate) attrs: Vec<String>,
 }
 
-pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
+pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> {
+    let mut file = File::create(file_path)
+        .map_err(|error| format!("failed to create args file: {error:?}"))?;
+
+    // We now put the common arguments into the file we created.
+    let mut content = vec!["--crate-type=bin".to_string()];
+
+    for cfg in &options.cfgs {
+        content.push(format!("--cfg={cfg}"));
+    }
+    if !options.check_cfgs.is_empty() {
+        content.push("-Zunstable-options".to_string());
+        for check_cfg in &options.check_cfgs {
+            content.push(format!("--check-cfg={check_cfg}"));
+        }
+    }
+
+    if let Some(sysroot) = &options.maybe_sysroot {
+        content.push(format!("--sysroot={}", sysroot.display()));
+    }
+    for lib_str in &options.lib_strs {
+        content.push(format!("-L{lib_str}"));
+    }
+    for extern_str in &options.extern_strs {
+        content.push(format!("--extern={extern_str}"));
+    }
+    content.push("-Ccodegen-units=1".to_string());
+    for codegen_options_str in &options.codegen_options_strs {
+        content.push(format!("-C{codegen_options_str}"));
+    }
+    for unstable_option_str in &options.unstable_opts_strs {
+        content.push(format!("-Z{unstable_option_str}"));
+    }
+
+    let content = content.join("\n");
+
+    file.write(content.as_bytes())
+        .map_err(|error| format!("failed to write arguments to temporary file: {error:?}"))?;
+    Ok(())
+}
+
+fn get_doctest_dir() -> io::Result<TempDir> {
+    TempFileBuilder::new().prefix("rustdoctest").tempdir()
+}
+
+pub(crate) fn run(
+    dcx: &rustc_errors::DiagCtxt,
+    options: RustdocOptions,
+) -> Result<(), ErrorGuaranteed> {
     let input = config::Input::File(options.input.clone());
 
     let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
@@ -118,6 +168,15 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
     let externs = options.externs.clone();
     let json_unused_externs = options.json_unused_externs;
 
+    let temp_dir = match get_doctest_dir()
+        .map_err(|error| format!("failed to create temporary directory: {error:?}"))
+    {
+        Ok(temp_dir) => temp_dir,
+        Err(error) => return crate::wrap_return(dcx, Err(error)),
+    };
+    let file_path = temp_dir.path().join("rustdoc-cfgs");
+    crate::wrap_return(dcx, generate_args_file(&file_path, &options))?;
+
     let (tests, unused_extern_reports, compiling_test_count) =
         interface::run_compiler(config, |compiler| {
             compiler.enter(|queries| {
@@ -134,6 +193,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
                         Some(compiler.sess.psess.clone_source_map()),
                         None,
                         enable_per_target_ignores,
+                        file_path,
                     );
 
                     let mut hir_collector = HirCollector {
@@ -322,44 +382,35 @@ fn run_test(
     test: &str,
     crate_name: &str,
     line: usize,
-    rustdoc_options: RustdocOptions,
+    rustdoc_options: IndividualTestOptions,
     mut lang_string: LangString,
     no_run: bool,
-    runtool: Option<String>,
-    runtool_args: Vec<String>,
-    target: TargetTriple,
     opts: &GlobalTestOptions,
     edition: Edition,
-    outdir: DirState,
     path: PathBuf,
-    test_id: &str,
     report_unused_externs: impl Fn(UnusedExterns),
 ) -> Result<(), TestFailure> {
-    let (test, line_offset, supports_color) =
-        make_test(test, Some(crate_name), lang_string.test_harness, opts, edition, Some(test_id));
+    let (test, line_offset, supports_color) = make_test(
+        test,
+        Some(crate_name),
+        lang_string.test_harness,
+        opts,
+        edition,
+        Some(&rustdoc_options.test_id),
+    );
 
     // Make sure we emit well-formed executable names for our target.
-    let rust_out = add_exe_suffix("rust_out".to_owned(), &target);
-    let output_file = outdir.path().join(rust_out);
+    let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target);
+    let output_file = rustdoc_options.outdir.path().join(rust_out);
 
     let rustc_binary = rustdoc_options
         .test_builder
         .as_deref()
         .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
     let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
-    compiler.arg("--crate-type").arg("bin");
-    for cfg in &rustdoc_options.cfgs {
-        compiler.arg("--cfg").arg(&cfg);
-    }
-    if !rustdoc_options.check_cfgs.is_empty() {
-        compiler.arg("-Z").arg("unstable-options");
-        for check_cfg in &rustdoc_options.check_cfgs {
-            compiler.arg("--check-cfg").arg(&check_cfg);
-        }
-    }
-    if let Some(sysroot) = rustdoc_options.maybe_sysroot {
-        compiler.arg("--sysroot").arg(sysroot);
-    }
+
+    compiler.arg(&format!("@{}", rustdoc_options.arg_file.display()));
+
     compiler.arg("--edition").arg(&edition.to_string());
     compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path);
     compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", format!("{}", line as isize - line_offset as isize));
@@ -367,29 +418,17 @@ fn run_test(
     if lang_string.test_harness {
         compiler.arg("--test");
     }
-    if rustdoc_options.json_unused_externs.is_enabled() && !lang_string.compile_fail {
+    if rustdoc_options.is_json_unused_externs_enabled && !lang_string.compile_fail {
         compiler.arg("--error-format=json");
         compiler.arg("--json").arg("unused-externs");
-        compiler.arg("-Z").arg("unstable-options");
         compiler.arg("-W").arg("unused_crate_dependencies");
+        compiler.arg("-Z").arg("unstable-options");
     }
-    for lib_str in &rustdoc_options.lib_strs {
-        compiler.arg("-L").arg(&lib_str);
-    }
-    for extern_str in &rustdoc_options.extern_strs {
-        compiler.arg("--extern").arg(&extern_str);
-    }
-    compiler.arg("-Ccodegen-units=1");
-    for codegen_options_str in &rustdoc_options.codegen_options_strs {
-        compiler.arg("-C").arg(&codegen_options_str);
-    }
-    for unstable_option_str in &rustdoc_options.unstable_opts_strs {
-        compiler.arg("-Z").arg(&unstable_option_str);
-    }
-    if no_run && !lang_string.compile_fail && rustdoc_options.persist_doctests.is_none() {
+
+    if no_run && !lang_string.compile_fail && rustdoc_options.should_persist_doctests {
         compiler.arg("--emit=metadata");
     }
-    compiler.arg("--target").arg(match target {
+    compiler.arg("--target").arg(match rustdoc_options.target {
         TargetTriple::TargetTriple(s) => s,
         TargetTriple::TargetJson { path_for_rustdoc, .. } => {
             path_for_rustdoc.to_str().expect("target path must be valid unicode").to_string()
@@ -485,10 +524,10 @@ fn run_test(
     let mut cmd;
 
     let output_file = make_maybe_absolute_path(output_file);
-    if let Some(tool) = runtool {
+    if let Some(tool) = rustdoc_options.runtool {
         let tool = make_maybe_absolute_path(tool.into());
         cmd = Command::new(tool);
-        cmd.args(runtool_args);
+        cmd.args(rustdoc_options.runtool_args);
         cmd.arg(output_file);
     } else {
         cmd = Command::new(output_file);
@@ -897,6 +936,56 @@ fn partition_source(s: &str, edition: Edition) -> (String, String, String) {
     (before, after, crates)
 }
 
+pub(crate) struct IndividualTestOptions {
+    test_builder: Option<PathBuf>,
+    test_builder_wrappers: Vec<PathBuf>,
+    is_json_unused_externs_enabled: bool,
+    should_persist_doctests: bool,
+    error_format: ErrorOutputType,
+    test_run_directory: Option<PathBuf>,
+    nocapture: bool,
+    arg_file: PathBuf,
+    outdir: DirState,
+    runtool: Option<String>,
+    runtool_args: Vec<String>,
+    target: TargetTriple,
+    test_id: String,
+}
+
+impl IndividualTestOptions {
+    fn new(options: &RustdocOptions, arg_file: &Path, test_id: String) -> Self {
+        let outdir = if let Some(ref path) = options.persist_doctests {
+            let mut path = path.clone();
+            path.push(&test_id);
+
+            if let Err(err) = std::fs::create_dir_all(&path) {
+                eprintln!("Couldn't create directory for doctest executables: {err}");
+                panic::resume_unwind(Box::new(()));
+            }
+
+            DirState::Perm(path)
+        } else {
+            DirState::Temp(get_doctest_dir().expect("rustdoc needs a tempdir"))
+        };
+
+        Self {
+            test_builder: options.test_builder.clone(),
+            test_builder_wrappers: options.test_builder_wrappers.clone(),
+            is_json_unused_externs_enabled: options.json_unused_externs.is_enabled(),
+            should_persist_doctests: options.persist_doctests.is_none(),
+            error_format: options.error_format,
+            test_run_directory: options.test_run_directory.clone(),
+            nocapture: options.nocapture,
+            arg_file: arg_file.into(),
+            outdir,
+            runtool: options.runtool.clone(),
+            runtool_args: options.runtool_args.clone(),
+            target: options.target.clone(),
+            test_id,
+        }
+    }
+}
+
 pub(crate) trait Tester {
     fn add_test(&mut self, test: String, config: LangString, line: usize);
     fn get_line(&self) -> usize {
@@ -941,6 +1030,7 @@ pub(crate) struct Collector {
     visited_tests: FxHashMap<(String, usize), usize>,
     unused_extern_reports: Arc<Mutex<Vec<UnusedExterns>>>,
     compiling_test_count: AtomicUsize,
+    arg_file: PathBuf,
 }
 
 impl Collector {
@@ -952,6 +1042,7 @@ impl Collector {
         source_map: Option<Lrc<SourceMap>>,
         filename: Option<PathBuf>,
         enable_per_target_ignores: bool,
+        arg_file: PathBuf,
     ) -> Collector {
         Collector {
             tests: Vec::new(),
@@ -967,6 +1058,7 @@ impl Collector {
             visited_tests: FxHashMap::default(),
             unused_extern_reports: Default::default(),
             compiling_test_count: AtomicUsize::new(0),
+            arg_file,
         }
     }
 
@@ -1009,13 +1101,9 @@ impl Tester for Collector {
         let crate_name = self.crate_name.clone();
         let opts = self.opts.clone();
         let edition = config.edition.unwrap_or(self.rustdoc_options.edition);
-        let rustdoc_options = self.rustdoc_options.clone();
-        let runtool = self.rustdoc_options.runtool.clone();
-        let runtool_args = self.rustdoc_options.runtool_args.clone();
-        let target = self.rustdoc_options.target.clone();
-        let target_str = target.to_string();
+        let target_str = self.rustdoc_options.target.to_string();
         let unused_externs = self.unused_extern_reports.clone();
-        let no_run = config.no_run || rustdoc_options.no_run;
+        let no_run = config.no_run || self.rustdoc_options.no_run;
         if !config.compile_fail {
             self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
         }
@@ -1049,23 +1137,9 @@ impl Tester for Collector {
                 self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0)
             },
         );
-        let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() {
-            path.push(&test_id);
 
-            if let Err(err) = std::fs::create_dir_all(&path) {
-                eprintln!("Couldn't create directory for doctest executables: {err}");
-                panic::resume_unwind(Box::new(()));
-            }
-
-            DirState::Perm(path)
-        } else {
-            DirState::Temp(
-                TempFileBuilder::new()
-                    .prefix("rustdoctest")
-                    .tempdir()
-                    .expect("rustdoc needs a tempdir"),
-            )
-        };
+        let rustdoc_test_options =
+            IndividualTestOptions::new(&self.rustdoc_options, &self.arg_file, test_id);
 
         debug!("creating test {name}: {test}");
         self.tests.push(test::TestDescAndFn {
@@ -1096,17 +1170,12 @@ impl Tester for Collector {
                     &test,
                     &crate_name,
                     line,
-                    rustdoc_options,
+                    rustdoc_test_options,
                     config,
                     no_run,
-                    runtool,
-                    runtool_args,
-                    target,
                     &opts,
                     edition,
-                    outdir,
                     path,
-                    &test_id,
                     report_unused_externs,
                 );
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 18651875130..b78fb4c4eee 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -664,7 +664,7 @@ fn usage(argv0: &str) {
 /// A result type used by several functions under `main()`.
 type MainResult = Result<(), ErrorGuaranteed>;
 
-fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult {
+pub(crate) fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult {
     match res {
         Ok(()) => dcx.has_errors().map_or(Ok(()), Err),
         Err(err) => Err(dcx.err(err)),
@@ -731,7 +731,7 @@ fn main_args(
 
     match (options.should_test, options.markdown_input()) {
         (true, true) => return wrap_return(&diag, markdown::test(options)),
-        (true, false) => return doctest::run(options),
+        (true, false) => return doctest::run(&diag, options),
         (false, true) => {
             let input = options.input.clone();
             let edition = options.edition;
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index b661ced0169..dcd2cf02a30 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -3,11 +3,13 @@ use std::fs::{create_dir_all, read_to_string, File};
 use std::io::prelude::*;
 use std::path::Path;
 
+use tempfile::tempdir;
+
 use rustc_span::edition::Edition;
 use rustc_span::DUMMY_SP;
 
 use crate::config::{Options, RenderOptions};
-use crate::doctest::{Collector, GlobalTestOptions};
+use crate::doctest::{generate_args_file, Collector, GlobalTestOptions};
 use crate::html::escape::Escape;
 use crate::html::markdown;
 use crate::html::markdown::{
@@ -146,6 +148,12 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
         .map_err(|err| format!("{input}: {err}", input = options.input.display()))?;
     let mut opts = GlobalTestOptions::default();
     opts.no_crate_inject = true;
+
+    let temp_dir =
+        tempdir().map_err(|error| format!("failed to create temporary directory: {error:?}"))?;
+    let file_path = temp_dir.path().join("rustdoc-cfgs");
+    generate_args_file(&file_path, &options)?;
+
     let mut collector = Collector::new(
         options.input.display().to_string(),
         options.clone(),
@@ -154,6 +162,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
         None,
         Some(options.input),
         options.enable_per_target_ignores,
+        file_path,
     );
     collector.set_position(DUMMY_SP);
     let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 88d9f762a87..8e27b3ccefd 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -163,7 +163,7 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
         // TODO: This check currently bails if the local variable has no initializer.
         // That is overly conservative - the lint should fire even if there was no initializer,
         // but the variable has been initialized before `lhs` was evaluated.
-        if let Some(Node::Local(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p))
+        if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p))
             && local.init.is_none()
         {
             return false;
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 66206d1a059..8683cb86e8a 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -6,7 +6,7 @@ use clippy_utils::{is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, Ty, TyKind};
+use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
@@ -139,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for InferVisitor {
 
 fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match cx.tcx.parent_hir_node(expr.hir_id) {
-        Node::Local(Local { ty: Some(ty), .. }) => {
+        Node::LetStmt(LetStmt { ty: Some(ty), .. }) => {
             let mut v = InferVisitor::default();
             v.visit_ty(ty);
             !v.0
diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
index 662737a14a4..f42bafce4dd 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
         && let ty::RawPtr(_, to_mutbl) = cast_to.kind()
         && let Some(use_cx) = expr_use_ctxt(cx, expr)
         // TODO: only block the lint if `cast_expr` is a temporary
-        && !matches!(use_cx.node, ExprUseNode::Local(_) | ExprUseNode::ConstStatic(_))
+        && !matches!(use_cx.node, ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
     {
         let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
         let fn_name = match to_mutbl {
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 08341ff32f3..148d52cb5dd 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -66,7 +66,7 @@ pub(super) fn check<'tcx>(
         && let QPath::Resolved(None, Path { res, .. }) = qpath
         && let Res::Local(hir_id) = res
         && let parent = cx.tcx.parent_hir_node(*hir_id)
-        && let Node::Local(local) = parent
+        && let Node::LetStmt(local) = parent
     {
         if let Some(ty) = local.ty
             && let TyKind::Path(qpath) = ty.kind
@@ -275,7 +275,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
                 }
             // Local usage
             } else if let Res::Local(hir_id) = res
-                && let Node::Local(l) = cx.tcx.parent_hir_node(hir_id)
+                && let Node::LetStmt(l) = cx.tcx.parent_hir_node(hir_id)
             {
                 if let Some(e) = l.init
                     && is_cast_from_ty_alias(cx, e, cast_from)
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index d820413e111..e921b9b46a6 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::for_each_expr_with_closures;
 use clippy_utils::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
-use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind};
+use rustc_hir::{Block, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -58,7 +58,7 @@ static COLLECTIONS: [Symbol; 9] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         // Look for local variables whose type is a container. Search surrounding bock for read access.
         if match_acceptable_type(cx, local, &COLLECTIONS)
             && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
     }
 }
 
-fn match_acceptable_type(cx: &LateContext<'_>, local: &Local<'_>, collections: &[rustc_span::Symbol]) -> bool {
+fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool {
     let ty = cx.typeck_results().pat_ty(local.pat);
     collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
     // String type is a lang item but not a diagnostic item for now so we need a separate check
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
index 80a537b9f94..a32201d8079 100644
--- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
                 // Ignore function parameters
                 return;
             },
-            Node::Local(local) if local.ty.is_some() => {
+            Node::LetStmt(local) if local.ty.is_some() => {
                 // Ignore let bindings with explicit type
                 return;
             },
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 0ea53c39280..619e933b4ff 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
-use rustc_hir::{Local, LocalSource, PatKind};
+use rustc_hir::{LetStmt, LocalSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{GenericArgKind, IsSuggestable};
@@ -138,7 +138,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if matches!(local.source, LocalSource::Normal)
             && !in_external_macro(cx.tcx.sess, local.span)
             && let PatKind::Wild = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 5f3f9b43f45..593b29154b4 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
-use rustc_hir::{Local, TyKind};
+use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
@@ -26,7 +26,7 @@ declare_clippy_lint! {
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
 impl LateLintPass<'_> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
         if !in_external_macro(cx.tcx.sess, local.span)
             && let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer = &ty.kind // that type is '_'
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 0f35514b8ad..670a78d58c3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
                         if let Node::Pat(pat) = node
                             && let PatKind::Binding(bind_ann, ..) = pat.kind
                             && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut))
-                            && let Node::Local(parent_let_expr) = cx.tcx.parent_hir_node(hir_id)
+                            && let Node::LetStmt(parent_let_expr) = cx.tcx.parent_hir_node(hir_id)
                             && let Some(init) = parent_let_expr.init
                         {
                             match init.kind {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 8bca33754e8..7b45cc95431 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -3,7 +3,7 @@ use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_loc
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_local, Visitor};
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, PatKind};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty};
@@ -141,7 +141,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn visit_local(&mut self, l: &'tcx Local<'_>) {
+    fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
         // Look for declarations of the variable
         if l.pat.hir_id == self.var_id
             && let PatKind::Binding(.., ident, _) = l.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index 93774b89768..bd04827a1f0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -5,13 +5,13 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::visitors::any_temporaries_need_ordered_drop;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, Local, MatchSource, Pat, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, StmtKind};
 use rustc_lint::LateContext;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
     let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
         ([stmt, stmts @ ..], expr) => {
-            if let StmtKind::Let(&Local {
+            if let StmtKind::Let(&LetStmt {
                 init: Some(e),
                 els: None,
                 ..
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index d070ee74985..194dd4752f9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -6,7 +6,7 @@ use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutabl
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
+use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, LetStmt, Mutability, PatKind, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::ty::adjustment::Adjust;
@@ -286,7 +286,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
             self.cx.tcx.hir()
         }
 
-        fn visit_local(&mut self, l: &'tcx Local<'_>) {
+        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
             if !self.after_loop {
                 l.pat.each_binding_or_first(&mut |_, id, _, _| {
                     if id == self.local_id {
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index 5cbab0ec977..f8f33cfc82e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::visitors::{is_local_used, local_used_once};
 use clippy_utils::{is_trait_method, path_to_local_id};
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind};
+use rustc_hir::{BindingAnnotation, ExprKind, LetStmt, Node, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
@@ -60,7 +60,7 @@ impl ManualHashOne {
 impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]);
 
 impl LateLintPass<'_> for ManualHashOne {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
         // `let mut hasher = seg.build_hasher();`
         if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind
             && let Some(init) = local.init
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 0bde62bd554..ab9bca170cf 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             // Apply only to params or locals with annotated types
             match cx.tcx.parent_hir_node(hir_id) {
                 Node::Param(..) => (),
-                Node::Local(local) => {
+                Node::LetStmt(local) => {
                     let Some(ty) = local.ty else { return };
                     if matches!(ty.kind, TyKind::Infer) {
                         return;
diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
index c8a48246e67..0f242e0b9e1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
@@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
-use rustc_hir::{ByRef, ExprKind, Local, MatchSource, PatKind, QPath};
+use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath};
 use rustc_lint::LateContext;
 
 use super::INFALLIBLE_DESTRUCTURING_MATCH;
 
-pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
+pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
     if !local.span.from_expansion()
         && let Some(expr) = local.init
         && let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 61977045fd4..864923b2773 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -148,7 +148,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
 fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
     if let Node::Expr(parent_arm_expr) = cx.tcx.parent_hir_node(ex.hir_id) {
         return match cx.tcx.parent_hir_node(parent_arm_expr.hir_id) {
-            Node::Local(parent_let_expr) => Some(AssignmentExpr::Local {
+            Node::LetStmt(parent_let_expr) => Some(AssignmentExpr::Local {
                 span: parent_let_expr.span,
                 pat_span: parent_let_expr.pat.span(),
             }),
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 50494f4819f..580d4a64296 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -27,7 +27,7 @@ mod wild_in_or_pats;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_opt, walk_span_to_context};
 use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text};
-use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
+use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat};
 use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -1124,7 +1124,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
         self.infallible_destructuring_match_linted |=
             local.els.is_none() && infallible_destructuring_match::check(cx, local);
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 3d3f29e5fc6..cee77f62b61 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -125,7 +125,7 @@ fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
     match cx.tcx.parent_hir_node(p_expr.hir_id) {
         // Compare match_expr ty with local in `let local = match match_expr {..}`
-        Node::Local(local) => {
+        Node::LetStmt(local) => {
             let results = cx.typeck_results();
             return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr));
         },
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index fb5c0c544a9..d4a5de3d1de 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -69,7 +69,7 @@ pub(super) fn check(
                 _ => false,
             },
             // local binding capturing a reference
-            Node::Local(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
+            Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
                 return;
             },
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 4c7c56e7174..19b7e97339d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re
             | ExprKind::Break(_, _) => true,
             _ => false,
         },
-        Some((Node::Stmt(_) | Node::Local(_), _)) => false,
+        Some((Node::Stmt(_) | Node::LetStmt(_), _)) => false,
         _ => true,
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 78540353005..9e2fd92255e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{
-    BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind,
+    BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind,
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -85,7 +85,7 @@ pub(super) fn check<'tcx>(
                 );
             }
         },
-        Node::Local(l) => {
+        Node::LetStmt(l) => {
             if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind
                 && let ty = cx.typeck_results().expr_ty(collect_expr)
                 && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList]
@@ -424,7 +424,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v>
     match stmt.kind {
         StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)),
         StmtKind::Item(..) => None,
-        StmtKind::Let(Local { init, pat, .. }) => {
+        StmtKind::Let(LetStmt { init, pat, .. }) => {
             if let PatKind::Binding(_, hir_id, ..) = pat.kind {
                 init.map(|init_expr| (init_expr, Some(hir_id)))
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
index 6c6846c4b47..9b0180d9369 100644
--- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
         && let Node::Expr(unwrap_call_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && is_unwrap_call(cx, unwrap_call_expr)
         && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id)
-        && let Node::Local(local) = parent
+        && let Node::LetStmt(local) = parent
         && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
         && let Some((local, _)) = mir
             .local_decls
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 55cd1a38ec9..946cdb49d27 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -8,7 +8,7 @@ use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{
-    BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
+    BindingAnnotation, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -128,7 +128,7 @@ fn check_manual_split_once_indirect(
 ) -> Option<()> {
     let ctxt = expr.span.ctxt();
     let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
-    if let (_, Node::Local(local)) = parents.next()?
+    if let (_, Node::LetStmt(local)) = parents.next()?
         && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
         && let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
         && let (_, Node::Block(enclosing_block)) = parents.next()?
@@ -198,7 +198,7 @@ fn indirect_usage<'tcx>(
     binding: HirId,
     ctxt: SyntaxContext,
 ) -> Option<IndirectUsage<'tcx>> {
-    if let StmtKind::Let(&Local {
+    if let StmtKind::Let(&LetStmt {
         pat: Pat {
             kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
             ..
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 988f3e86fcf..ccc8d17970e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -20,7 +20,7 @@ fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 
     // some common cases where turbofish isn't needed:
     // - assigned to a local variable with a type annotation
-    if let hir::Node::Local(local) = parent
+    if let hir::Node::LetStmt(local) = parent
         && local.ty.is_some()
     {
         return false;
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 12c7c18afde..656fb907fcd 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
             StmtKind::Let(local) => {
-                if let Local { init: Some(e), .. } = local {
+                if let LetStmt { init: Some(e), .. } = local {
                     DivergenceVisitor { cx }.visit_expr(e);
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index c32025fcbb6..79f0a398d55 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 4cda4b171e3..810799acb2e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -6,7 +6,7 @@ use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_loca
 use core::ops::ControlFlow;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{
-    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
+    BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
     StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -237,7 +237,7 @@ fn first_usage<'tcx>(
         })
 }
 
-fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> Option<String> {
+fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<String> {
     let span = local.span.with_hi(match local.ty {
         // let <pat>: <ty>;
         // ~~~~~~~~~~~~~~~
@@ -252,7 +252,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> O
 
 fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    local: &'tcx Local<'tcx>,
+    local: &'tcx LetStmt<'tcx>,
     local_stmt: &'tcx Stmt<'tcx>,
     block: &'tcx Block<'tcx>,
     binding_id: HirId,
@@ -363,9 +363,9 @@ fn check<'tcx>(
 }
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
-        if let Local {
+        if let LetStmt {
             init: None,
             pat:
                 &Pat {
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 2587b3881bb..896c99a7104 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -604,7 +604,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
 
             match get_expr_use_or_unification_node(self.cx.tcx, e) {
                 Some((Node::Stmt(_), _)) => (),
-                Some((Node::Local(l), _)) => {
+                Some((Node::LetStmt(l), _)) => {
                     // Only trace simple bindings. e.g `let x = y;`
                     if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind {
                         self.bindings.insert(id, args_idx);
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 831c291ed7c..f1db571e113 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -14,7 +14,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
+    BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -109,7 +109,7 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir
 }
 
 fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
-    if let StmtKind::Let(Local {
+    if let StmtKind::Let(LetStmt {
         pat,
         init: Some(init_expr),
         els: Some(els),
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 0ebdb031d5a..7f4735c6a88 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -3,7 +3,7 @@ use clippy_utils::get_enclosing_block;
 use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
 use clippy_utils::source::snippet;
 
-use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind};
+use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
             }
 
             if let StmtKind::Let(local) = stmt.kind
-                && let Local {
+                && let LetStmt {
                     pat, init: Some(init), ..
                 } = local
                 && let PatKind::Binding(_, id, ident, _) = pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 6528a7b369f..0f579f779df 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::needs_ordered_drop;
 use rustc_ast::Mutability;
 use rustc_hir::def::Res;
-use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor::PlaceBase;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -47,7 +47,7 @@ declare_clippy_lint! {
 declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
 
 impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if !local.span.is_desugaring(DesugaringKind::Async)
             // the pattern is a single by-value binding
             && let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index 079e6500e3c..96f6f0ec36f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -131,7 +131,7 @@ fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option<hir::PrimTy> {
 }
 
 impl LateLintPass<'_> for RedundantTypeAnnotations {
-    fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) {
+    fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::LetStmt<'tcx>) {
         if !is_lint_allowed(cx, REDUNDANT_TYPE_ANNOTATIONS, local.hir_id)
             // type annotation part
             && !local.span.from_expansion()
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index ca7a0c7c87b..c227b5b22f4 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use clippy_utils::{is_from_proc_macro, path_to_local_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
@@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
         self.searcher = None;
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind
             && !in_external_macro(cx.sess(), local.span)
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index df7bd4c8d1d..d98b37bda35 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -241,7 +241,7 @@ fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'
                 ExprKind::Match(e, _, _) | ExprKind::Let(&LetExpr { init: e, .. }) => Some(e),
                 _ => None,
             },
-            Node::Local(local) => local.init,
+            Node::LetStmt(local) => local.init,
             _ => None,
         };
         return init;
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 0d84a9ab395..564b065d0ba 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -159,7 +159,7 @@ fn all_bindings_are_for_conv<'tcx>(
         .iter()
         .map(|node| match node {
             Node::Pat(pat) => kind.eq(&pat.kind).then_some(pat.hir_id),
-            Node::Local(l) => Some(l.hir_id),
+            Node::LetStmt(l) => Some(l.hir_id),
             _ => None,
         })
         .all_equal()
@@ -170,7 +170,7 @@ fn all_bindings_are_for_conv<'tcx>(
         && local_parents.first().is_some_and(|node| {
             let Some(ty) = match node {
                 Node::Pat(pat) => Some(pat.hir_id),
-                Node::Local(l) => Some(l.hir_id),
+                Node::LetStmt(l) => Some(l.hir_id),
                 _ => None,
             }
             .map(|hir_id| cx.typeck_results().node_type(hir_id)) else {
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 2ad15ac8312..0802cb2b7c7 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -12,7 +12,7 @@ mod vec_box;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
+    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitItem,
     TraitItemKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -425,7 +425,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if let Some(ty) = local.ty {
             self.check_ty(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 0efa65b28e2..5fe4b74b3a7 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
-        let (hir::StmtKind::Let(&hir::Local { init: Some(expr), .. })
+        let (hir::StmtKind::Let(&hir::LetStmt { init: Some(expr), .. })
         | hir::StmtKind::Expr(expr)
         | hir::StmtKind::Semi(expr)) = stmt.kind
         else {
@@ -342,7 +342,7 @@ fn block_parents_have_safety_comment(
 ) -> bool {
     let (span, hir_id) = match cx.tcx.parent_hir_node(id) {
         Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) {
-            Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id),
+            Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
             Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 span,
@@ -358,12 +358,12 @@ fn block_parents_have_safety_comment(
         },
         Node::Stmt(hir::Stmt {
             kind:
-                hir::StmtKind::Let(hir::Local { span, hir_id, .. })
+                hir::StmtKind::Let(hir::LetStmt { span, hir_id, .. })
                 | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. })
                 | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
             ..
         })
-        | Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id),
+        | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
         Node::Item(hir::Item {
             kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
             span,
@@ -603,7 +603,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
     for (_, node) in map.parent_iter(body.hir_id) {
         match node {
             Node::Expr(e) => span = e.span,
-            Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (),
+            Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::LetStmt(_) => (),
             Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 ..
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 9406d160769..ffb909d7907 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -4,14 +4,14 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Local, MatchSource, Node, PatKind, QPath, TyKind};
+use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::{in_external_macro, is_from_async_await};
 use rustc_middle::ty;
 
 use super::LET_UNIT_VALUE;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
     // skip `let () = { ... }`
     if let PatKind::Tuple(fields, ..) = local.pat.kind
         && fields.is_empty()
@@ -102,7 +102,7 @@ fn expr_needs_inferred_result<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -
         return false;
     }
     while let Some(id) = locals_to_check.pop() {
-        if let Node::Local(l) = cx.tcx.parent_hir_node(id) {
+        if let Node::LetStmt(l) = cx.tcx.parent_hir_node(id) {
             if !l.ty.map_or(true, |ty| matches!(ty.kind, TyKind::Infer)) {
                 return false;
             }
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 0abd48e6423..e016bd3434b 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -3,7 +3,7 @@ mod unit_arg;
 mod unit_cmp;
 mod utils;
 
-use rustc_hir::{Expr, Local};
+use rustc_hir::{Expr, LetStmt};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
@@ -99,7 +99,7 @@ declare_clippy_lint! {
 declare_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_CMP, UNIT_ARG]);
 
 impl<'tcx> LateLintPass<'tcx> for UnitTypes {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         let_unit_value::check(cx, local);
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 3f4ab3e31cf..e6f799335d7 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
 use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_session::declare_lint_pass;
@@ -190,7 +190,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                             },
                         }
                     },
-                    Node::Local(Local { init: Some(init), .. }) => {
+                    Node::LetStmt(LetStmt { init: Some(init), .. }) => {
                         if arg_is_mut_peekable(self.cx, init) {
                             self.found_peek_call = true;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 1ebe1d6a2c4..c56c8ddc7a9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -1006,7 +1006,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
 
 fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     match cx.tcx.parent_hir_node(hir_id) {
-        hir::Node::Local(local) => Some(local),
+        hir::Node::LetStmt(local) => Some(local),
         hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index f4e277fd0c4..304a1379374 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -217,7 +217,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
     match peel_hir_expr_refs(expr).0.kind {
         ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
             Res::Local(hir_id) => {
-                if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
+                if let Node::LetStmt(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
                     path_to_matched_type(cx, init)
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 7cfcf3fe946..27ead55bf39 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -9,7 +9,7 @@ use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
 use clippy_utils::{get_parent_expr, higher, is_trait_method};
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Local, Mutability, Node, Pat, PatKind};
+use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
         match cx.tcx.parent_hir_node(expr.hir_id) {
             // search for `let foo = vec![_]` expressions where all uses of `foo`
             // adjust to slices or call a method that exist on slices (e.g. len)
-            Node::Local(Local {
+            Node::LetStmt(LetStmt {
                 ty: None,
                 pat:
                     Pat {
@@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                 }
             },
             // if the local pattern has a specified type, do not lint.
-            Node::Local(Local { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => {
+            Node::LetStmt(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => {
                 self.span_to_lint_map.insert(callsite, None);
             },
             // search for `for _ in vec![...]`
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index ac3b2bdaf65..b58a4fb8474 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -7,7 +7,7 @@ use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
+    BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
         self.searcher = None;
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
             && !in_external_macro(cx.sess(), local.span)
diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
index 852d04cd21b..143fecdd237 100644
--- a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
@@ -78,7 +78,7 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr:
         let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id);
         let return_type = cx.typeck_results().expr_ty(expr);
 
-        if let Node::Local(l) = parent_hir_node {
+        if let Node::LetStmt(l) = parent_hir_node {
             array_span_lint(
                 cx,
                 l.span,
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index a526ba97af6..3b1b99caebe 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -99,7 +99,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
     ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
-    ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
+    ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
     QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
@@ -184,7 +184,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr
 pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
     if let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
         && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..))
-        && let Node::Local(local) = cx.tcx.parent_hir_node(hir_id)
+        && let Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id)
     {
         return local.init;
     }
@@ -1079,7 +1079,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                 },
                 _ => break,
             },
-            Node::Local(l) => match pat_capture_kind(cx, l.pat) {
+            Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) {
                 CaptureKind::Value => break,
                 capture @ CaptureKind::Ref(_) => return capture,
             },
@@ -1357,7 +1357,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
                 ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
                 _ => (),
             },
-            Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
+            Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) => (),
             _ => break,
         }
     }
@@ -1462,7 +1462,7 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
     let mut child_id = expr.hir_id;
     for (parent_id, node) in tcx.hir().parent_iter(child_id) {
-        if let Node::Local(Local {
+        if let Node::LetStmt(LetStmt {
             init: Some(init),
             els: Some(els),
             ..
@@ -1482,7 +1482,7 @@ pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
     let mut child_id = expr.hir_id;
     for (parent_id, node) in tcx.hir().parent_iter(child_id) {
-        if let Node::Local(Local { els: Some(els), .. }) = node
+        if let Node::LetStmt(LetStmt { els: Some(els), .. }) = node
             && els.hir_id == child_id
         {
             return true;
@@ -2158,7 +2158,7 @@ pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
             Node::Stmt(Stmt {
                 kind: StmtKind::Expr(_)
                     | StmtKind::Semi(_)
-                    | StmtKind::Let(Local {
+                    | StmtKind::Let(LetStmt {
                         pat: Pat {
                             kind: PatKind::Wild,
                             ..
@@ -2639,7 +2639,7 @@ pub struct ExprUseCtxt<'tcx> {
 /// The node which consumes a value.
 pub enum ExprUseNode<'tcx> {
     /// Assignment to, or initializer for, a local
-    Local(&'tcx Local<'tcx>),
+    LetStmt(&'tcx LetStmt<'tcx>),
     /// Initializer for a const or static item.
     ConstStatic(OwnerId),
     /// Implicit or explicit return from a function.
@@ -2671,7 +2671,7 @@ impl<'tcx> ExprUseNode<'tcx> {
     /// Gets the needed type as it's defined without any type inference.
     pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
         match *self {
-            Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
+            Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
             Self::ConstStatic(id) => Some(DefinedTy::Mir(
                 cx.param_env
                     .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
@@ -2731,7 +2731,7 @@ impl<'tcx> ExprUseNode<'tcx> {
                 let sig = cx.tcx.fn_sig(id).skip_binder();
                 Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
             },
-            Self::Local(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
+            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
         }
     }
 }
@@ -2770,7 +2770,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio
     .continue_value()
     .map(|(use_node, child_id)| {
         let node = match use_node {
-            Node::Local(l) => ExprUseNode::Local(l),
+            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
             Node::ExprField(field) => ExprUseNode::Field(field),
 
             Node::Item(&Item {
@@ -3158,7 +3158,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<
             }
         }
 
-        fn visit_local(&mut self, l: &'tcx Local<'_>) {
+        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
             if let Some(e) = l.init {
                 self.visit_expr(e);
             }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index dadb0d662ce..cabebf89bec 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -174,7 +174,7 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbCheck(_), _)
+        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks, _)
         | Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 7913926928f..762830ffd78 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -242,7 +242,7 @@ fn path_segment_certainty(
             Node::Param(..) => Certainty::Certain(None),
             // A local's type is certain if its type annotation is certain or it has an initializer whose
             // type is certain.
-            Node::Local(local) => {
+            Node::LetStmt(local) => {
                 let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
                 let rhs = local
                     .init
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index c70005c2c58..1097fc6db72 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -206,7 +206,7 @@ jobs:
         run: |
           PR=$(gh pr create -B master --title 'Automatic Rustup' --body '')
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
-            --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
+            --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \
             --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.lock b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.lock
index 7bf23225ea5..2a5f8f32254 100644
--- a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.lock
+++ b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.lock
@@ -3,5 +3,5 @@
 version = 3
 
 [[package]]
-name = "invalidate"
+name = "range-iteration"
 version = "0.1.0"
diff --git a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.toml b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.toml
index 14cf0882f0b..3f0146f6259 100644
--- a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.toml
+++ b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "invalidate"
+name = "range-iteration"
 version = "0.1.0"
 edition = "2021"
 
diff --git a/src/tools/miri/bench-cargo-miri/invalidate/src/main.rs b/src/tools/miri/bench-cargo-miri/range-iteration/src/main.rs
index fa8deb851c3..1ef35ee6b3c 100644
--- a/src/tools/miri/bench-cargo-miri/invalidate/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/range-iteration/src/main.rs
@@ -1,4 +1,5 @@
+//! This generates a lot of work for the AllocId part of the GC.
 fn main() {
     // The end of the range is just chosen to make the benchmark run for a few seconds.
-    for _ in 0..200_000 {}
+    for _ in 0..50_000 {}
 }
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index e32968d8178..9b89f016a77 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-ee03c286cfdca26fa5b2a4ee40957625d2c826ff
+c3b05c6e5b5b59613350b8c2875b0add67ed74df
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 6955e649b4d..c12382527e7 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -179,6 +179,26 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
             });
         }
     }
+
+    fn after_analysis<'tcx>(
+        &mut self,
+        _: &rustc_interface::interface::Compiler,
+        queries: &'tcx rustc_interface::Queries<'tcx>,
+    ) -> Compilation {
+        queries.global_ctxt().unwrap().enter(|tcx| {
+            if self.target_crate {
+                // cargo-miri has patched the compiler flags to make these into check-only builds,
+                // but we are still emulating regular rustc builds, which would perform post-mono
+                // const-eval during collection. So let's also do that here, even if we might be
+                // running with `--emit=metadata`. In particular this is needed to make
+                // `compile_fail` doc tests trigger post-mono errors.
+                // In general `collect_and_partition_mono_items` is not safe to call in check-only
+                // builds, but we are setting `-Zalways-encode-mir` which avoids those issues.
+                let _ = tcx.collect_and_partition_mono_items(());
+            }
+        });
+        Compilation::Continue
+    }
 }
 
 fn show_error(msg: &impl std::fmt::Display) -> ! {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index b26bbd16902..96ff298402d 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -18,6 +18,7 @@ use crate::borrow_tracker::{
     stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
     GlobalStateInner, ProtectorKind,
 };
+use crate::concurrency::data_race::{NaReadType, NaWriteType};
 use crate::*;
 
 use diagnostics::{RetagCause, RetagInfo};
@@ -751,7 +752,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
                     assert_eq!(access, AccessKind::Write);
                     // Make sure the data race model also knows about this.
                     if let Some(data_race) = alloc_extra.data_race.as_mut() {
-                        data_race.write(alloc_id, range, machine)?;
+                        data_race.write(
+                            alloc_id,
+                            range,
+                            NaWriteType::Retag,
+                            Some(place.layout.ty),
+                            machine,
+                        )?;
                     }
                 }
             }
@@ -794,7 +801,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
                         assert_eq!(access, AccessKind::Read);
                         // Make sure the data race model also knows about this.
                         if let Some(data_race) = alloc_extra.data_race.as_ref() {
-                            data_race.read(alloc_id, range, &this.machine)?;
+                            data_race.read(
+                                alloc_id,
+                                range,
+                                NaReadType::Retag,
+                                Some(place.layout.ty),
+                                &this.machine,
+                            )?;
                         }
                     }
                     Ok(())
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 56ca1240f60..a3d49756e4c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -9,8 +9,11 @@ use rustc_middle::{
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{Abi, Size};
 
-use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
 use crate::*;
+use crate::{
+    borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind},
+    concurrency::data_race::NaReadType,
+};
 
 pub mod diagnostics;
 mod perms;
@@ -312,7 +315,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         // Also inform the data race model (but only if any bytes are actually affected).
         if range.size.bytes() > 0 {
             if let Some(data_race) = alloc_extra.data_race.as_ref() {
-                data_race.read(alloc_id, range, &this.machine)?;
+                data_race.read(
+                    alloc_id,
+                    range,
+                    NaReadType::Retag,
+                    Some(place.layout.ty),
+                    &this.machine,
+                )?;
             }
         }
 
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 127d97bd5af..d51160b2831 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -49,7 +49,7 @@ use std::{
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::{Idx, IndexVec};
-use rustc_middle::mir;
+use rustc_middle::{mir, ty::Ty};
 use rustc_span::Span;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
@@ -200,18 +200,38 @@ enum AtomicAccessType {
     Rmw,
 }
 
-/// Type of write operation: allocating memory
-/// non-atomic writes and deallocating memory
-/// are all treated as writes for the purpose
-/// of the data-race detector.
+/// Type of a non-atomic read operation.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum NaWriteType {
+pub enum NaReadType {
+    /// Standard unsynchronized write.
+    Read,
+
+    // An implicit read generated by a retag.
+    Retag,
+}
+
+impl NaReadType {
+    fn description(self) -> &'static str {
+        match self {
+            NaReadType::Read => "non-atomic read",
+            NaReadType::Retag => "retag read",
+        }
+    }
+}
+
+/// Type of a non-atomic write operation: allocating memory, non-atomic writes, and
+/// deallocating memory are all treated as writes for the purpose of the data-race detector.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum NaWriteType {
     /// Allocate memory.
     Allocate,
 
     /// Standard unsynchronized write.
     Write,
 
+    // An implicit write generated by a retag.
+    Retag,
+
     /// Deallocate memory.
     /// Note that when memory is deallocated first, later non-atomic accesses
     /// will be reported as use-after-free, not as data races.
@@ -224,6 +244,7 @@ impl NaWriteType {
         match self {
             NaWriteType::Allocate => "creating a new allocation",
             NaWriteType::Write => "non-atomic write",
+            NaWriteType::Retag => "retag write",
             NaWriteType::Deallocate => "deallocation",
         }
     }
@@ -231,7 +252,7 @@ impl NaWriteType {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum AccessType {
-    NaRead,
+    NaRead(NaReadType),
     NaWrite(NaWriteType),
     AtomicLoad,
     AtomicStore,
@@ -239,29 +260,48 @@ enum AccessType {
 }
 
 impl AccessType {
-    fn description(self) -> &'static str {
-        match self {
-            AccessType::NaRead => "non-atomic read",
+    fn description(self, ty: Option<Ty<'_>>, size: Option<Size>) -> String {
+        let mut msg = String::new();
+
+        if let Some(size) = size {
+            msg.push_str(&format!("{}-byte {}", size.bytes(), msg))
+        }
+
+        msg.push_str(match self {
+            AccessType::NaRead(w) => w.description(),
             AccessType::NaWrite(w) => w.description(),
             AccessType::AtomicLoad => "atomic load",
             AccessType::AtomicStore => "atomic store",
             AccessType::AtomicRmw => "atomic read-modify-write",
+        });
+
+        if let Some(ty) = ty {
+            msg.push_str(&format!(" of type `{}`", ty));
         }
+
+        msg
     }
 
     fn is_atomic(self) -> bool {
         match self {
             AccessType::AtomicLoad | AccessType::AtomicStore | AccessType::AtomicRmw => true,
-            AccessType::NaRead | AccessType::NaWrite(_) => false,
+            AccessType::NaRead(_) | AccessType::NaWrite(_) => false,
         }
     }
 
     fn is_read(self) -> bool {
         match self {
-            AccessType::AtomicLoad | AccessType::NaRead => true,
+            AccessType::AtomicLoad | AccessType::NaRead(_) => true,
             AccessType::NaWrite(_) | AccessType::AtomicStore | AccessType::AtomicRmw => false,
         }
     }
+
+    fn is_retag(self) -> bool {
+        matches!(
+            self,
+            AccessType::NaRead(NaReadType::Retag) | AccessType::NaWrite(NaWriteType::Retag)
+        )
+    }
 }
 
 /// Memory Cell vector clock metadata
@@ -502,12 +542,14 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &mut ThreadClockSet,
         index: VectorIdx,
+        read_type: NaReadType,
         current_span: Span,
     ) -> Result<(), DataRace> {
         trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, thread_clocks);
         if !current_span.is_dummy() {
             thread_clocks.clock[index].span = current_span;
         }
+        thread_clocks.clock[index].set_read_type(read_type);
         if self.write_was_before(&thread_clocks.clock) {
             let race_free = if let Some(atomic) = self.atomic() {
                 // We must be ordered-after all atomic accesses, reads and writes.
@@ -875,7 +917,8 @@ impl VClockAlloc {
     /// This finds the two racing threads and the type
     /// of data-race that occurred. This will also
     /// return info about the memory location the data-race
-    /// occurred in.
+    /// occurred in. The `ty` parameter is used for diagnostics, letting
+    /// the user know which type was involved in the access.
     #[cold]
     #[inline(never)]
     fn report_data_race<'tcx>(
@@ -885,6 +928,7 @@ impl VClockAlloc {
         access: AccessType,
         access_size: Size,
         ptr_dbg: Pointer<AllocId>,
+        ty: Option<Ty<'_>>,
     ) -> InterpResult<'tcx> {
         let (current_index, current_clocks) = global.current_thread_state(thread_mgr);
         let mut other_size = None; // if `Some`, this was a size-mismatch race
@@ -908,7 +952,7 @@ impl VClockAlloc {
                 write_clock = mem_clocks.write();
                 (AccessType::NaWrite(mem_clocks.write_type), mem_clocks.write.0, &write_clock)
             } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &current_clocks.clock) {
-                (AccessType::NaRead, idx, &mem_clocks.read)
+                (AccessType::NaRead(mem_clocks.read[idx].read_type()), idx, &mem_clocks.read)
             // Finally, mixed-size races.
             } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size {
                 // This is only a race if we are not synchronized with all atomic accesses, so find
@@ -950,37 +994,33 @@ impl VClockAlloc {
         Err(err_machine_stop!(TerminationInfo::DataRace {
             involves_non_atomic,
             extra,
+            retag_explain: access.is_retag() || other_access.is_retag(),
             ptr: ptr_dbg,
             op1: RacingOp {
-                action: if let Some(other_size) = other_size {
-                    format!("{}-byte {}", other_size.bytes(), other_access.description())
-                } else {
-                    other_access.description().to_owned()
-                },
+                action: other_access.description(None, other_size),
                 thread_info: other_thread_info,
                 span: other_clock.as_slice()[other_thread.index()].span_data(),
             },
             op2: RacingOp {
-                action: if other_size.is_some() {
-                    format!("{}-byte {}", access_size.bytes(), access.description())
-                } else {
-                    access.description().to_owned()
-                },
+                action: access.description(ty, other_size.map(|_| access_size)),
                 thread_info: current_thread_info,
                 span: current_clocks.clock.as_slice()[current_index.index()].span_data(),
             },
         }))?
     }
 
-    /// Detect data-races for an unsynchronized read operation, will not perform
+    /// Detect data-races for an unsynchronized read operation. It will not perform
     /// data-race detection if `race_detecting()` is false, either due to no threads
     /// being created or if it is temporarily disabled during a racy read or write
     /// operation for which data-race detection is handled separately, for example
-    /// atomic read operations.
+    /// atomic read operations. The `ty` parameter is used for diagnostics, letting
+    /// the user know which type was read.
     pub fn read<'tcx>(
         &self,
         alloc_id: AllocId,
         access_range: AllocRange,
+        read_type: NaReadType,
+        ty: Option<Ty<'_>>,
         machine: &MiriMachine<'_, '_>,
     ) -> InterpResult<'tcx> {
         let current_span = machine.current_span();
@@ -992,7 +1032,7 @@ impl VClockAlloc {
                 alloc_ranges.iter_mut(access_range.start, access_range.size)
             {
                 if let Err(DataRace) =
-                    mem_clocks.read_race_detect(&mut thread_clocks, index, current_span)
+                    mem_clocks.read_race_detect(&mut thread_clocks, index, read_type, current_span)
                 {
                     drop(thread_clocks);
                     // Report data-race.
@@ -1000,9 +1040,10 @@ impl VClockAlloc {
                         global,
                         &machine.threads,
                         mem_clocks,
-                        AccessType::NaRead,
+                        AccessType::NaRead(read_type),
                         access_range.size,
                         Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
+                        ty,
                     );
                 }
             }
@@ -1012,12 +1053,17 @@ impl VClockAlloc {
         }
     }
 
-    // Shared code for detecting data-races on unique access to a section of memory
-    fn unique_access<'tcx>(
+    /// Detect data-races for an unsynchronized write operation. It will not perform
+    /// data-race detection if `race_detecting()` is false, either due to no threads
+    /// being created or if it is temporarily disabled during a racy read or write
+    /// operation. The `ty` parameter is used for diagnostics, letting
+    /// the user know which type was written.
+    pub fn write<'tcx>(
         &mut self,
         alloc_id: AllocId,
         access_range: AllocRange,
         write_type: NaWriteType,
+        ty: Option<Ty<'_>>,
         machine: &mut MiriMachine<'_, '_>,
     ) -> InterpResult<'tcx> {
         let current_span = machine.current_span();
@@ -1042,6 +1088,7 @@ impl VClockAlloc {
                         AccessType::NaWrite(write_type),
                         access_range.size,
                         Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
+                        ty,
                     );
                 }
             }
@@ -1050,37 +1097,6 @@ impl VClockAlloc {
             Ok(())
         }
     }
-
-    /// Detect data-races for an unsynchronized write operation, will not perform
-    /// data-race threads if `race_detecting()` is false, either due to no threads
-    /// being created or if it is temporarily disabled during a racy read or write
-    /// operation
-    pub fn write<'tcx>(
-        &mut self,
-        alloc_id: AllocId,
-        range: AllocRange,
-        machine: &mut MiriMachine<'_, '_>,
-    ) -> InterpResult<'tcx> {
-        self.unique_access(alloc_id, range, NaWriteType::Write, machine)
-    }
-
-    /// Detect data-races for an unsynchronized deallocate operation, will not perform
-    /// data-race threads if `race_detecting()` is false, either due to no threads
-    /// being created or if it is temporarily disabled during a racy read or write
-    /// operation
-    pub fn deallocate<'tcx>(
-        &mut self,
-        alloc_id: AllocId,
-        size: Size,
-        machine: &mut MiriMachine<'_, '_>,
-    ) -> InterpResult<'tcx> {
-        self.unique_access(
-            alloc_id,
-            alloc_range(Size::ZERO, size),
-            NaWriteType::Deallocate,
-            machine,
-        )
-    }
 }
 
 impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {}
@@ -1279,7 +1295,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
                 let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap();
                 trace!(
                     "Atomic op({}) with ordering {:?} on {:?} (size={})",
-                    access.description(),
+                    access.description(None, None),
                     &atomic,
                     place.ptr(),
                     size.bytes()
@@ -1307,6 +1323,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
                                         alloc_id,
                                         Size::from_bytes(mem_clocks_range.start),
                                     ),
+                                    None,
                                 )
                                 .map(|_| true);
                             }
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index fa93c9e00b1..fe719943dcb 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -4,9 +4,11 @@ use smallvec::SmallVec;
 use std::{
     cmp::Ordering,
     fmt::Debug,
-    ops::{Index, IndexMut},
+    ops::{Index, IndexMut, Shr},
 };
 
+use super::data_race::NaReadType;
+
 /// A vector clock index, this is associated with a thread id
 /// but in some cases one vector index may be shared with
 /// multiple thread ids if it's safe to do so.
@@ -50,13 +52,51 @@ const SMALL_VECTOR: usize = 4;
 /// so that diagnostics can report what code was responsible for an operation.
 #[derive(Clone, Copy, Debug)]
 pub struct VTimestamp {
-    time: u32,
+    /// The lowest bit indicates read type, the rest is the time.
+    /// `1` indicates a retag read, `0` a regular read.
+    time_and_read_type: u32,
     pub span: Span,
 }
 
 impl VTimestamp {
-    pub const ZERO: VTimestamp = VTimestamp { time: 0, span: DUMMY_SP };
+    pub const ZERO: VTimestamp = VTimestamp::new(0, NaReadType::Read, DUMMY_SP);
+
+    #[inline]
+    const fn encode_time_and_read_type(time: u32, read_type: NaReadType) -> u32 {
+        let read_type_bit = match read_type {
+            NaReadType::Read => 0,
+            NaReadType::Retag => 1,
+        };
+        // Put the `read_type` in the lowest bit and `time` in the rest
+        read_type_bit | time.checked_mul(2).expect("Vector clock overflow")
+    }
+
+    #[inline]
+    const fn new(time: u32, read_type: NaReadType, span: Span) -> Self {
+        Self { time_and_read_type: Self::encode_time_and_read_type(time, read_type), span }
+    }
+
+    #[inline]
+    fn time(&self) -> u32 {
+        self.time_and_read_type.shr(1)
+    }
 
+    #[inline]
+    fn set_time(&mut self, time: u32) {
+        self.time_and_read_type = Self::encode_time_and_read_type(time, self.read_type());
+    }
+
+    #[inline]
+    pub fn read_type(&self) -> NaReadType {
+        if self.time_and_read_type & 1 == 0 { NaReadType::Read } else { NaReadType::Retag }
+    }
+
+    #[inline]
+    pub fn set_read_type(&mut self, read_type: NaReadType) {
+        self.time_and_read_type = Self::encode_time_and_read_type(self.time(), read_type);
+    }
+
+    #[inline]
     pub fn span_data(&self) -> SpanData {
         self.span.data()
     }
@@ -64,7 +104,7 @@ impl VTimestamp {
 
 impl PartialEq for VTimestamp {
     fn eq(&self, other: &Self) -> bool {
-        self.time == other.time
+        self.time() == other.time()
     }
 }
 
@@ -78,7 +118,7 @@ impl PartialOrd for VTimestamp {
 
 impl Ord for VTimestamp {
     fn cmp(&self, other: &Self) -> Ordering {
-        self.time.cmp(&other.time)
+        self.time().cmp(&other.time())
     }
 }
 
@@ -130,7 +170,7 @@ impl VClock {
         let idx = idx.index();
         let mut_slice = self.get_mut_with_min_len(idx + 1);
         let idx_ref = &mut mut_slice[idx];
-        idx_ref.time = idx_ref.time.checked_add(1).expect("Vector clock overflow");
+        idx_ref.set_time(idx_ref.time().checked_add(1).expect("Vector clock overflow"));
         if !current_span.is_dummy() {
             idx_ref.span = current_span;
         }
@@ -379,8 +419,8 @@ impl IndexMut<VectorIdx> for VClock {
 ///  test suite
 #[cfg(test)]
 mod tests {
-
     use super::{VClock, VTimestamp, VectorIdx};
+    use crate::concurrency::data_race::NaReadType;
     use rustc_span::DUMMY_SP;
     use std::cmp::Ordering;
 
@@ -448,7 +488,13 @@ mod tests {
         while let Some(0) = slice.last() {
             slice = &slice[..slice.len() - 1]
         }
-        VClock(slice.iter().copied().map(|time| VTimestamp { time, span: DUMMY_SP }).collect())
+        VClock(
+            slice
+                .iter()
+                .copied()
+                .map(|time| VTimestamp::new(time, NaReadType::Read, DUMMY_SP))
+                .collect(),
+        )
     }
 
     fn assert_order(l: &[u32], r: &[u32], o: Option<Ordering>) {
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 03428b081c5..99d37065bac 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -46,6 +46,7 @@ pub enum TerminationInfo {
         op1: RacingOp,
         op2: RacingOp,
         extra: Option<&'static str>,
+        retag_explain: bool,
     },
 }
 
@@ -263,12 +264,17 @@ pub fn report_error<'tcx, 'mir>(
                 vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))],
             Int2PtrWithStrictProvenance =>
                 vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))],
-            DataRace { op1, extra, .. } => {
+            DataRace { op1, extra, retag_explain, .. } => {
                 let mut helps = vec![(Some(op1.span), format!("and (1) occurred earlier here"))];
                 if let Some(extra) = extra {
                     helps.push((None, format!("{extra}")));
                     helps.push((None, format!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model")));
                 }
+                if *retag_explain {
+                    helps.push((None, "retags occur on all (re)borrows and as well as when references are copied or moved".to_owned()));
+                    helps.push((None, "retags permit optimizations that insert speculative reads or writes".to_owned()));
+                    helps.push((None, "therefore from the perspective of data races, a retag has the same implications as a read or write".to_owned()));
+                }
                 helps.push((None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")));
                 helps.push((None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")));
                 helps
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 416d0cda8f1..7821aa9efd4 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(rustc_private)]
 #![feature(cell_update)]
+#![feature(const_option)]
 #![feature(float_gamma)]
 #![feature(generic_nonzero)]
 #![feature(map_try_insert)]
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 29315c4933c..2137de6a29b 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -35,6 +35,9 @@ use crate::{
     *,
 };
 
+use self::concurrency::data_race::NaReadType;
+use self::concurrency::data_race::NaWriteType;
+
 /// First real-time signal.
 /// `signal(7)` says this must be between 32 and 64 and specifies 34 or 35
 /// as typical values.
@@ -372,10 +375,8 @@ pub struct PrimitiveLayouts<'tcx> {
 impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
     fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
         let tcx = layout_cx.tcx;
-        let mut_raw_ptr =
-            Ty::new_mut_ptr(tcx, tcx.types.unit);
-        let const_raw_ptr =
-            Ty::new_imm_ptr(tcx, tcx.types.unit);
+        let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit);
+        let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
         Ok(Self {
             unit: layout_cx.layout_of(Ty::new_unit(tcx))?,
             i8: layout_cx.layout_of(tcx.types.i8)?,
@@ -1240,7 +1241,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
                 .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Read));
         }
         if let Some(data_race) = &alloc_extra.data_race {
-            data_race.read(alloc_id, range, machine)?;
+            data_race.read(alloc_id, range, NaReadType::Read, None, machine)?;
         }
         if let Some(borrow_tracker) = &alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?;
@@ -1264,7 +1265,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
                 .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Write));
         }
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.write(alloc_id, range, machine)?;
+            data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?;
         }
         if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?;
@@ -1288,7 +1289,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
             machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
         }
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.deallocate(alloc_id, size, machine)?;
+            data_race.write(
+                alloc_id,
+                alloc_range(Size::ZERO, size),
+                NaWriteType::Deallocate,
+                None,
+                machine,
+            )?;
         }
         if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?;
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index c97a052f517..6973c0e9c35 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -33,6 +33,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "round"
             | "trunc"
             | "fsqrt"
+            | "fsin"
+            | "fcos"
+            | "fexp"
+            | "fexp2"
+            | "flog"
+            | "flog2"
+            | "flog10"
             | "ctlz"
             | "cttz"
             | "bswap"
@@ -45,17 +52,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 assert_eq!(dest_len, op_len);
 
                 #[derive(Copy, Clone)]
-                enum Op {
+                enum Op<'a> {
                     MirOp(mir::UnOp),
                     Abs,
-                    Sqrt,
                     Round(rustc_apfloat::Round),
                     Numeric(Symbol),
+                    HostOp(&'a str),
                 }
                 let which = match intrinsic_name {
                     "neg" => Op::MirOp(mir::UnOp::Neg),
                     "fabs" => Op::Abs,
-                    "fsqrt" => Op::Sqrt,
                     "ceil" => Op::Round(rustc_apfloat::Round::TowardPositive),
                     "floor" => Op::Round(rustc_apfloat::Round::TowardNegative),
                     "round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
@@ -64,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "cttz" => Op::Numeric(sym::cttz),
                     "bswap" => Op::Numeric(sym::bswap),
                     "bitreverse" => Op::Numeric(sym::bitreverse),
-                    _ => unreachable!(),
+                    _ => Op::HostOp(intrinsic_name),
                 };
 
                 for i in 0..dest_len {
@@ -89,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                                 FloatTy::F128 => unimplemented!("f16_f128"),
                             }
                         }
-                        Op::Sqrt => {
+                        Op::HostOp(host_op) => {
                             let ty::Float(float_ty) = op.layout.ty.kind() else {
                                 span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
                             };
@@ -98,13 +104,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                                 FloatTy::F16 => unimplemented!("f16_f128"),
                                 FloatTy::F32 => {
                                     let f = op.to_scalar().to_f32()?;
-                                    let res = f.to_host().sqrt().to_soft();
+                                    let f_host = f.to_host();
+                                    let res = match host_op {
+                                        "fsqrt" => f_host.sqrt(),
+                                        "fsin" => f_host.sin(),
+                                        "fcos" => f_host.cos(),
+                                        "fexp" => f_host.exp(),
+                                        "fexp2" => f_host.exp2(),
+                                        "flog" => f_host.ln(),
+                                        "flog2" => f_host.log2(),
+                                        "flog10" => f_host.log10(),
+                                        _ => bug!(),
+                                    };
+                                    let res = res.to_soft();
                                     let res = this.adjust_nan(res, &[f]);
                                     Scalar::from(res)
                                 }
                                 FloatTy::F64 => {
                                     let f = op.to_scalar().to_f64()?;
-                                    let res = f.to_host().sqrt().to_soft();
+                                    let f_host = f.to_host();
+                                    let res = match host_op {
+                                        "fsqrt" => f_host.sqrt(),
+                                        "fsin" => f_host.sin(),
+                                        "fcos" => f_host.cos(),
+                                        "fexp" => f_host.exp(),
+                                        "fexp2" => f_host.exp2(),
+                                        "flog" => f_host.ln(),
+                                        "flog2" => f_host.log2(),
+                                        "flog10" => f_host.log10(),
+                                        _ => bug!(),
+                                    };
+                                    let res = res.to_soft();
                                     let res = this.adjust_nan(res, &[f]);
                                     Scalar::from(res)
                                 }
@@ -427,7 +457,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let bitmask_len = u32::try_from(bitmask_len).unwrap();
 
                 // To read the mask, we transmute it to an integer.
-                // That does the right thing wrt endianess.
+                // That does the right thing wrt endianness.
                 let mask_ty = this.machine.layouts.uint(mask.layout.size).unwrap();
                 let mask = mask.transmute(mask_ty, this)?;
                 let mask: u64 = this.read_scalar(&mask)?.to_bits(mask_ty.size)?.try_into().unwrap();
@@ -479,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     }
                 }
                 // We have to change the type of the place to be able to write `res` into it. This
-                // transmutes the integer to an array, which does the right thing wrt endianess.
+                // transmutes the integer to an array, which does the right thing wrt endianness.
                 let dest =
                     dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
                 this.write_int(res, &dest)?;
diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs
index 1f17ffb88c8..49408fda3ae 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/event.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs
@@ -38,7 +38,7 @@ impl FileDescriptor for Event {
     }
 
     /// A write call adds the 8-byte integer value supplied in
-    /// its buffer (in native endianess) to the counter.  The maximum value that may be
+    /// its buffer (in native endianness) to the counter.  The maximum value that may be
     /// stored in the counter is the largest unsigned 64-bit value
     /// minus 1 (i.e., 0xfffffffffffffffe).  If the addition would
     /// cause the counter's value to exceed the maximum, then the
@@ -57,7 +57,7 @@ impl FileDescriptor for Event {
     ) -> InterpResult<'tcx, io::Result<usize>> {
         let v1 = self.val.get();
         let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
-        // Convert from target endianess to host endianess.
+        // Convert from target endianness to host endianness.
         let num = match tcx.sess.target.endian {
             Endian::Little => u64::from_le_bytes(bytes),
             Endian::Big => u64::from_be_bytes(bytes),
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 7cd397625dc..7b7921219e6 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -88,6 +88,19 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                 this.write_immediate(*sub, &this.project_field(dest, 1)?)?;
             }
 
+            // Used to implement the `_mm_pause` function.
+            // The intrinsic is used to hint the processor that the code is in a spin-loop.
+            // It is compiled down to a `pause` instruction. When SSE2 is not available,
+            // the instruction behaves like a no-op, so it is always safe to call the
+            // intrinsic.
+            "sse2.pause" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                // Only exhibit the spin-loop hint behavior when SSE2 is enabled.
+                if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
+                    this.yield_active_thread();
+                }
+            }
+
             name if name.starts_with("sse.") => {
                 return sse::EvalContextExt::emulate_x86_sse_intrinsic(
                     this, link_name, abi, args, dest,
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 18ff5d809e3..eb2cc9d37c8 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -580,12 +580,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
                 }
             }
-            // Used to implement the `_mm_pause` function.
-            // The intrinsic is used to hint the processor that the code is in a spin-loop.
-            "pause" => {
-                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.yield_active_thread();
-            }
             _ => return Ok(EmulateForeignItemResult::NotSupported),
         }
         Ok(EmulateForeignItemResult::NeedsJumping)
diff --git a/src/tools/miri/test-cargo-miri/src/lib.rs b/src/tools/miri/test-cargo-miri/src/lib.rs
index 66c8aa2eac5..e6b8c4ef65b 100644
--- a/src/tools/miri/test-cargo-miri/src/lib.rs
+++ b/src/tools/miri/test-cargo-miri/src/lib.rs
@@ -1,13 +1,31 @@
 /// Doc-test test
+///
 /// ```rust
 /// assert!(cargo_miri_test::make_true());
 /// ```
+///
+/// `no_run` test:
+///
 /// ```rust,no_run
 /// assert!(!cargo_miri_test::make_true());
 /// ```
+///
+/// `compile_fail` test:
+///
 /// ```rust,compile_fail
 /// assert!(cargo_miri_test::make_true() == 5);
 /// ```
+///
+/// Post-monomorphization error in `compile_fail` test:
+///
+/// ```rust,compile_fail
+/// struct Fail<T>(T);
+/// impl<T> Fail<T> {
+///     const C: () = panic!();
+/// }
+///
+/// let _val = Fail::<i32>::C;
+/// ```
 #[no_mangle]
 pub fn make_true() -> bool {
     issue_1567::use_the_dependency();
diff --git a/src/tools/miri/test-cargo-miri/test.default.stdout.ref b/src/tools/miri/test-cargo-miri/test.default.stdout.ref
index 9a17f3d61b6..922d2120bed 100644
--- a/src/tools/miri/test-cargo-miri/test.default.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.default.stdout.ref
@@ -10,7 +10,7 @@ running 6 tests
 test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out
 
 
-running 4 tests
-....
-test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+running 5 tests
+.....
+test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref
index c618956656a..5c819dd5323 100644
--- a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref
@@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out
 
 running 0 tests
 
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in $TIME
 
diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
index eb1fe56df07..3edaf10f3dc 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
@@ -17,7 +17,7 @@ fn thread_1(p: SendPtr) {
 fn thread_2(p: SendPtr) {
     let p = p.0;
     unsafe {
-        *p = 5; //~ ERROR: /Data race detected between \(1\) non-atomic (read|write) on thread `unnamed-[0-9]+` and \(2\) non-atomic write on thread `unnamed-[0-9]+`/
+        *p = 5; //~ ERROR: /Data race detected between \(1\) retag (read|write) on thread `unnamed-[0-9]+` and \(2\) non-atomic write on thread `unnamed-[0-9]+`/
     }
 }
 
diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr
index c5b65e6f747..6f4b52fb887 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) retag write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         *p = 5;
-   |         ^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |         ^^^^^^ Data race detected between (1) retag write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         let _r = &mut *p;
    |                  ^^^^^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr
index 62f139f6f08..fa0012f9b26 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         *p = 5;
-   |         ^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |         ^^^^^^ Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         let _r = &mut *p;
    |                  ^^^^^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
new file mode 100644
index 00000000000..89fdd2a01eb
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
@@ -0,0 +1,19 @@
+#![feature(core_intrinsics)]
+#![feature(rustc_attrs)]
+
+use std::intrinsics::typed_swap;
+use std::ptr::addr_of_mut;
+
+fn invalid_array() {
+    let mut a = [1_u8; 100];
+    let mut b = [2_u8; 100];
+    unsafe {
+        let a = addr_of_mut!(a).cast::<[bool; 100]>();
+        let b = addr_of_mut!(b).cast::<[bool; 100]>();
+        typed_swap(a, b); //~ERROR: constructing invalid value
+    }
+}
+
+fn main() {
+    invalid_array();
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
new file mode 100644
index 00000000000..15f01c1c095
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean
+  --> $DIR/typed-swap-invalid-array.rs:LL:CC
+   |
+LL |         typed_swap(a, b);
+   |         ^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `invalid_array` at $DIR/typed-swap-invalid-array.rs:LL:CC
+note: inside `main`
+  --> $DIR/typed-swap-invalid-array.rs:LL:CC
+   |
+LL |     invalid_array();
+   |     ^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
new file mode 100644
index 00000000000..9d014a523f8
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
@@ -0,0 +1,19 @@
+#![feature(core_intrinsics)]
+#![feature(rustc_attrs)]
+
+use std::intrinsics::typed_swap;
+use std::ptr::addr_of_mut;
+
+fn invalid_scalar() {
+    let mut a = 1_u8;
+    let mut b = 2_u8;
+    unsafe {
+        let a = addr_of_mut!(a).cast::<bool>();
+        let b = addr_of_mut!(b).cast::<bool>();
+        typed_swap(a, b); //~ERROR: constructing invalid value
+    }
+}
+
+fn main() {
+    invalid_scalar();
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr
new file mode 100644
index 00000000000..262ca202f9f
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean
+  --> $DIR/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |         typed_swap(a, b);
+   |         ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `invalid_scalar` at $DIR/typed-swap-invalid-scalar.rs:LL:CC
+note: inside `main`
+  --> $DIR/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |     invalid_scalar();
+   |     ^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
index 5db89c89b77..3de517055ec 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
@@ -13,7 +13,7 @@ fn main() {
         let ptr = ptr;
         // We do a protected mutable retag (but no write!) in this thread.
         fn retag(_x: &mut i32) {}
-        retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-1`
+        retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-1`
     });
 
     // We do a read in the main thread.
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr
index 2ce757013d5..47ae4b5d46d 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_protected_read.rs:LL:CC
    |
 LL |         retag(unsafe { &mut *ptr.0 });
-   |                        ^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |                        ^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_protected_read.rs:LL:CC
    |
 LL |     unsafe { ptr.0.read() };
    |              ^^^^^^^^^^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
index 01a2e9ac474..25c92ddf6ca 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
@@ -15,7 +15,7 @@ fn thread_1(p: SendPtr) {
 fn thread_2(p: SendPtr) {
     let p = p.0;
     unsafe {
-        *p = 5; //~ ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) non-atomic write on thread `unnamed-2`
+        *p = 5; //~ ERROR: Data race detected between (1) retag read on thread `unnamed-1` and (2) non-atomic write on thread `unnamed-2`
     }
 }
 
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
index d3c8d14e2a1..9fe9fbeda44 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_read.rs:LL:CC
    |
 LL |         *p = 5;
-   |         ^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |         ^^^^^^ Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_read.rs:LL:CC
    |
 LL |         let _r = &*p;
    |                  ^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs
index 370b09f512c..4e9fa12c181 100644
--- a/src/tools/miri/tests/pass/intptrcast.rs
+++ b/src/tools/miri/tests/pass/intptrcast.rs
@@ -149,6 +149,31 @@ fn functions() {
     }
 }
 
+/// Example that should be UB but due to wildcard pointers being too permissive
+/// we don't notice.
+fn should_be_ub() {
+    let alloc1 = 1u8;
+    let alloc2 = 2u8;
+    // Expose both allocations
+    let addr1: usize = &alloc1 as *const u8 as usize;
+    let addr2: usize = &alloc2 as *const u8 as usize;
+
+    // Cast addr1 back to a pointer. In Miri, this gives it Wildcard provenance.
+    let wildcard = addr1 as *const u8;
+    unsafe {
+        // Read through the wildcard
+        assert_eq!(*wildcard, 1);
+        // Offset the pointer to another allocation.
+        // Note that we are doing this arithmetic that does not require we stay within bounds of the allocation.
+        let wildcard = wildcard.wrapping_offset(addr2 as isize - addr1 as isize);
+        // This should report UB:
+        assert_eq!(*wildcard, 2);
+        // ... but it doesn't. A pointer's provenance specifies a single allocation that it is allowed to read from.
+        // And wrapping_offset only modifies the address, not the provenance.
+        // So which allocation is wildcard allowed to access? It cannot be both.
+    }
+}
+
 fn main() {
     cast();
     cast_dangling();
@@ -162,4 +187,5 @@ fn main() {
     ptr_eq_integer();
     zst_deref_of_dangling();
     functions();
+    should_be_ub();
 }
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs
new file mode 100644
index 00000000000..c8b92fd5458
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs
@@ -0,0 +1,25 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=-sse2
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+fn main() {
+    assert!(!is_x86_feature_detected!("sse2"));
+
+    unsafe {
+        // This is a SSE2 intrinsic, but it behaves as a no-op when SSE2
+        // is not available, so it is always safe to call.
+        _mm_pause();
+    }
+}
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
index e636d6c8aaf..e0088b9eb24 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
@@ -54,6 +54,11 @@ mod tests {
             }
         }
 
+        fn test_mm_pause() {
+            unsafe { _mm_pause() }
+        }
+        test_mm_pause();
+
         #[target_feature(enable = "sse2")]
         unsafe fn test_mm_avg_epu8() {
             let (a, b) = (_mm_set1_epi8(3), _mm_set1_epi8(9));
diff --git a/src/tools/miri/tests/pass/main_fn.rs b/src/tools/miri/tests/pass/main_fn.rs
deleted file mode 100644
index 4cdd034f30e..00000000000
--- a/src/tools/miri/tests/pass/main_fn.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-mod foo {
-    pub(crate) fn bar() {}
-}
-
-use foo::bar as main;
diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs
index 399913a757b..cdb441b450b 100644
--- a/src/tools/miri/tests/pass/portable-simd.rs
+++ b/src/tools/miri/tests/pass/portable-simd.rs
@@ -526,6 +526,23 @@ fn simd_intrinsics() {
     }
 }
 
+fn simd_float_intrinsics() {
+    use intrinsics::*;
+
+    // These are just smoke tests to ensure the intrinsics can be called.
+    unsafe {
+        let a = f32x4::splat(10.0);
+        simd_fsqrt(a);
+        simd_fsin(a);
+        simd_fcos(a);
+        simd_fexp(a);
+        simd_fexp2(a);
+        simd_flog(a);
+        simd_flog2(a);
+        simd_flog10(a);
+    }
+}
+
 fn simd_masked_loadstore() {
     // The buffer is deliberarely too short, so reading the last element would be UB.
     let buf = [3i32; 3];
@@ -559,5 +576,6 @@ fn main() {
     simd_gather_scatter();
     simd_round();
     simd_intrinsics();
+    simd_float_intrinsics();
     simd_masked_loadstore();
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index e5e7b559c92..419b04231b5 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -9,8 +9,8 @@ pub fn out_dir() -> PathBuf {
     env::var_os("TMPDIR").unwrap().into()
 }
 
-fn setup_common_build_cmd() -> Command {
-    let rustc = env::var("RUSTC").unwrap();
+fn setup_common_build_cmd(command: &str) -> Command {
+    let rustc = env::var(command).unwrap();
     let mut cmd = Command::new(rustc);
     cmd.arg("--out-dir").arg(out_dir()).arg("-L").arg(out_dir());
     cmd
@@ -33,6 +33,10 @@ pub fn aux_build() -> AuxBuildInvocationBuilder {
     AuxBuildInvocationBuilder::new()
 }
 
+pub fn rustdoc() -> Rustdoc {
+    Rustdoc::new()
+}
+
 #[derive(Debug)]
 pub struct RustcInvocationBuilder {
     cmd: Command,
@@ -40,7 +44,7 @@ pub struct RustcInvocationBuilder {
 
 impl RustcInvocationBuilder {
     fn new() -> Self {
-        let cmd = setup_common_build_cmd();
+        let cmd = setup_common_build_cmd("RUSTC");
         Self { cmd }
     }
 
@@ -74,7 +78,7 @@ pub struct AuxBuildInvocationBuilder {
 
 impl AuxBuildInvocationBuilder {
     fn new() -> Self {
-        let mut cmd = setup_common_build_cmd();
+        let mut cmd = setup_common_build_cmd("RUSTC");
         cmd.arg("--crate-type=lib");
         Self { cmd }
     }
@@ -97,6 +101,35 @@ impl AuxBuildInvocationBuilder {
     }
 }
 
+#[derive(Debug)]
+pub struct Rustdoc {
+    cmd: Command,
+}
+
+impl Rustdoc {
+    fn new() -> Self {
+        let cmd = setup_common_build_cmd("RUSTDOC");
+        Self { cmd }
+    }
+
+    pub fn arg(&mut self, arg: &str) -> &mut Self {
+        self.cmd.arg(arg);
+        self
+    }
+
+    #[track_caller]
+    pub fn run(&mut self) -> Output {
+        let caller_location = std::panic::Location::caller();
+        let caller_line_number = caller_location.line();
+
+        let output = self.cmd.output().unwrap();
+        if !output.status.success() {
+            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+        }
+        output
+    }
+}
+
 fn run_common(bin_name: &str) -> (Command, Output) {
     let target = env::var("TARGET").unwrap();
 
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index cb46e65999d..1a39d212386 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -121,6 +121,7 @@ fn default_dcx(
             fallback_bundle,
             fatal_dcx: DiagCtxt::new(emitter),
             fatal_note: None,
+            emit_fatal_diagnostic: false,
         })
     } else {
         emitter
@@ -209,7 +210,7 @@ impl ParseSess {
             rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
             false,
         );
-        self.raw_psess.dcx.make_silent(fallback_bundle, None);
+        self.raw_psess.dcx.make_silent(fallback_bundle, None, false);
     }
 
     pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
diff --git a/tests/assembly/x86_64-typed-swap.rs b/tests/assembly/x86_64-typed-swap.rs
new file mode 100644
index 00000000000..95e87519e6c
--- /dev/null
+++ b/tests/assembly/x86_64-typed-swap.rs
@@ -0,0 +1,53 @@
+//@ revisions: WIN LIN
+//@ [WIN] only-windows
+//@ [LIN] only-linux
+//@ only-x86_64
+//@ assembly-output: emit-asm
+//@ compile-flags: --crate-type=lib -O
+
+use std::arch::x86_64::__m128;
+use std::mem::swap;
+
+// CHECK-LABEL: swap_i32:
+#[no_mangle]
+pub fn swap_i32(x: &mut i32, y: &mut i32) {
+    // CHECK: movl (%[[ARG1:.+]]), %[[T1:.+]]
+    // CHECK: movl (%[[ARG2:.+]]), %[[T2:.+]]
+    // CHECK: movl %[[T2]], (%[[ARG1]])
+    // CHECK: movl %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
+
+// CHECK-LABEL: swap_pair:
+#[no_mangle]
+pub fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
+    // CHECK: movq (%[[ARG1]]), %[[T1:.+]]
+    // CHECK: movq (%[[ARG2]]), %[[T2:.+]]
+    // CHECK: movq %[[T2]], (%[[ARG1]])
+    // CHECK: movq %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
+
+// CHECK-LABEL: swap_str:
+#[no_mangle]
+pub fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
+    // CHECK: movups (%[[ARG1]]), %[[T1:xmm.]]
+    // CHECK: movups (%[[ARG2]]), %[[T2:xmm.]]
+    // CHECK: movups %[[T2]], (%[[ARG1]])
+    // CHECK: movups %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
+
+// CHECK-LABEL: swap_simd:
+#[no_mangle]
+pub fn swap_simd(x: &mut __m128, y: &mut __m128) {
+    // CHECK: movaps (%[[ARG1]]), %[[T1:xmm.]]
+    // CHECK: movaps (%[[ARG2]]), %[[T2:xmm.]]
+    // CHECK: movaps %[[T2]], (%[[ARG1]])
+    // CHECK: movaps %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
diff --git a/tests/codegen/intrinsics/typed_swap.rs b/tests/codegen/intrinsics/typed_swap.rs
new file mode 100644
index 00000000000..b55fb8ee36f
--- /dev/null
+++ b/tests/codegen/intrinsics/typed_swap.rs
@@ -0,0 +1,78 @@
+//@ revisions: OPT0 OPT3
+//@ [OPT0] compile-flags: -Copt-level=0
+//@ [OPT3] compile-flags: -Copt-level=3
+//@ compile-flags: -C no-prepopulate-passes
+//@ only-64bit (so I don't need to worry about usize)
+// ignore-tidy-linelength (the memcpy calls get long)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::typed_swap;
+
+// CHECK-LABEL: @swap_unit(
+#[no_mangle]
+pub unsafe fn swap_unit(x: &mut (), y: &mut ()) {
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    typed_swap(x, y)
+}
+
+// CHECK-LABEL: @swap_i32(
+#[no_mangle]
+pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) {
+    // CHECK-NOT: alloca
+
+    // CHECK: %[[TEMP:.+]] = load i32, ptr %x, align 4
+    // CHECK-SAME: !noundef
+    // OPT0: %[[TEMP2:.+]] = load i32, ptr %y, align 4
+    // OPT0-SAME: !noundef
+    // OPT0: store i32 %[[TEMP2]], ptr %x, align 4
+    // OPT0-NOT: memcpy
+    // OPT3-NOT: load
+    // OPT3: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 4, i1 false)
+    // CHECK: store i32 %[[TEMP]], ptr %y, align 4
+    // CHECK: ret void
+    typed_swap(x, y)
+}
+
+// CHECK-LABEL: @swap_pair(
+#[no_mangle]
+pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
+    // CHECK-NOT: alloca
+
+    // CHECK: load i32
+    // CHECK-SAME: !noundef
+    // CHECK: load i32
+    // CHECK-SAME: !noundef
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false)
+    // CHECK: store i32
+    // CHECK: store i32
+    typed_swap(x, y)
+}
+
+// CHECK-LABEL: @swap_str(
+#[no_mangle]
+pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
+    // CHECK-NOT: alloca
+
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: load i64
+    // CHECK-SAME: !noundef
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false)
+    // CHECK: store ptr
+    // CHECK: store i64
+    typed_swap(x, y)
+}
+
+// OPT0-LABEL: @swap_string(
+#[no_mangle]
+pub unsafe fn swap_string(x: &mut String, y: &mut String) {
+    // OPT0: %[[TEMP:.+]] = alloca {{.+}}, align 8
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TEMP]], ptr align 8 %x, i64 24, i1 false)
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 24, i1 false)
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %y, ptr align 8 %[[TEMP]], i64 24, i1 false)
+    typed_swap(x, y)
+}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
index 6f47f5e3355..1332338b26a 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
@@ -34,6 +34,12 @@ pub struct Bar(i32);
 #[repr(transparent)]
 pub struct Type3<T>(T);
 
+// repr(transparent) wrapper which engages in self-reference
+#[repr(transparent)]
+pub struct Type4(Type4Helper<Type4>);
+#[repr(transparent)]
+pub struct Type4Helper<T>(*mut T);
+
 pub fn foo1(_: Type1) { }
 // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 pub fn foo2(_: Type1, _: Type1) { }
@@ -52,6 +58,13 @@ pub fn foo8(_: Type3<Bar>, _: Type3<Bar>) { }
 // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 pub fn foo9(_: Type3<Bar>, _: Type3<Bar>, _: Type3<Bar>) { }
 // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: Type4) { }
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: Type4, _: Type4) { }
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: Type4, _: Type4, _: Type4) { }
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
 
 // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooE"}
 // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_E"}
@@ -62,3 +75,6 @@ pub fn foo9(_: Type3<Bar>, _: Type3<Bar>, _: Type3<Bar>) { }
 // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarE"}
 // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_E"}
 // CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_S_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_S0_E"}
diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs
index 5fdf4a5804a..4dcfed2a53a 100644
--- a/tests/codegen/swap-small-types.rs
+++ b/tests/codegen/swap-small-types.rs
@@ -70,10 +70,7 @@ pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) {
     // CHECK-NOT: alloca
     // CHECK: load ptr
     // CHECK: load i64
-    // CHECK: load ptr
-    // CHECK: load i64
-    // CHECK: store ptr
-    // CHECK: store i64
+    // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 16, i1 false)
     // CHECK: store ptr
     // CHECK: store i64
     swap(x, y)
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index a958e5541fa..21cf745b680 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index b073e27729e..ee58a974480 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index 0a9f339ddba..9fc9c8ed409 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index bbc791148af..30d93347afd 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 3a11677f6f0..3a46edbc849 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index 9e7e08866b9..3c71214c35f 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index beadfbc07b6..4557e7b26d6 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 9ea86956b83..5ab2d5e0fdc 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
index 9986d903501..617501217cf 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
@@ -1,6 +1,5 @@
 //@ unit-test: DataflowConstProp
 //@ compile-flags: -Zmir-enable-passes=+GVN,+Inline
-//@ ignore-debug assertions change the output MIR
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs
index 189cd7951fb..fc3691049eb 100644
--- a/tests/mir-opt/funky_arms.rs
+++ b/tests/mir-opt/funky_arms.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ compile-flags: --crate-type lib -Cdebug-assertions=no
 
 #![feature(flt2dec)]
 
diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs
index 2fd18f3d5eb..12b00e76a11 100644
--- a/tests/mir-opt/inline/unchecked_shifts.rs
+++ b/tests/mir-opt/inline/unchecked_shifts.rs
@@ -2,7 +2,6 @@
 #![crate_type = "lib"]
 #![feature(unchecked_shifts)]
 
-//@ ignore-debug: the debug assertions prevent the inlining we are testing for
 //@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
 
 // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
diff --git a/tests/mir-opt/inline/unwrap_unchecked.rs b/tests/mir-opt/inline/unwrap_unchecked.rs
index e44e4e23a2c..13c76c5bb53 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.rs
+++ b/tests/mir-opt/inline/unwrap_unchecked.rs
@@ -1,8 +1,7 @@
 #![crate_type = "lib"]
 
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ ignore-debug: the debug assertions prevent the inlining we are testing for
-//@ compile-flags: -Zmir-opt-level=2 -Zinline-mir -Cdebug-assertions=no
+//@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
 
 // EMIT_MIR unwrap_unchecked.unwrap_unchecked.Inline.diff
 // EMIT_MIR unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
index 6f7853a3e97..028040edc85 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
@@ -17,6 +17,10 @@
 +                 let _5: ();
 +                 scope 5 {
 +                 }
++                 scope 6 (inlined core::ub_checks::check_language_ub) {
++                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
++                     }
++                 }
 +             }
 +         }
 +     }
@@ -37,7 +41,7 @@
 + 
 +     bb2: {
 +         StorageLive(_4);
-+         _4 = UbCheck(LanguageUb);
++         _4 = UbChecks();
 +         assume(_4);
 +         _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
 +     }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
index cac06d4af08..484fd37248c 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
@@ -17,6 +17,10 @@
 +                 let _5: ();
 +                 scope 5 {
 +                 }
++                 scope 6 (inlined core::ub_checks::check_language_ub) {
++                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
++                     }
++                 }
 +             }
 +         }
 +     }
@@ -41,7 +45,7 @@
 -         resume;
 +     bb2: {
 +         StorageLive(_4);
-+         _4 = UbCheck(LanguageUb);
++         _4 = UbChecks();
 +         assume(_4);
 +         _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
 +     }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
index 5c611650154..9cd7053871e 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
@@ -15,6 +15,10 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
                 let _4: ();
                 scope 5 {
                 }
+                scope 6 (inlined core::ub_checks::check_language_ub) {
+                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
             }
         }
     }
@@ -27,7 +31,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
 
     bb1: {
         StorageLive(_3);
-        _3 = UbCheck(LanguageUb);
+        _3 = UbChecks();
         assume(_3);
         _4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
     }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
index 5c611650154..9cd7053871e 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
@@ -15,6 +15,10 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
                 let _4: ();
                 scope 5 {
                 }
+                scope 6 (inlined core::ub_checks::check_language_ub) {
+                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
             }
         }
     }
@@ -27,7 +31,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
 
     bb1: {
         StorageLive(_3);
-        _3 = UbCheck(LanguageUb);
+        _3 = UbChecks();
         assume(_3);
         _4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
     }
diff --git a/tests/mir-opt/inline_coroutine_body.rs b/tests/mir-opt/inline_coroutine_body.rs
new file mode 100644
index 00000000000..be73bc49de5
--- /dev/null
+++ b/tests/mir-opt/inline_coroutine_body.rs
@@ -0,0 +1,28 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// skip-filecheck
+//@ unit-test: Inline
+//@ edition: 2021
+//@ compile-flags: -Zinline-mir-hint-threshold=10000 -Zinline-mir-threshold=10000 --crate-type=lib
+
+pub async fn run(permit: ActionPermit<'_, ()>, ctx: &mut core::task::Context<'_>) {
+    run2(permit, ctx);
+}
+
+// EMIT_MIR inline_coroutine_body.run2-{closure#0}.Inline.diff
+fn run2<T>(permit: ActionPermit<'_, T>, ctx: &mut core::task::Context) {
+    _ = || {
+        let mut fut = ActionPermit::perform(permit);
+        let fut = unsafe { core::pin::Pin::new_unchecked(&mut fut) };
+        _ = core::future::Future::poll(fut, ctx);
+    };
+}
+
+pub struct ActionPermit<'a, T> {
+    _guard: core::cell::Ref<'a, T>,
+}
+
+impl<'a, T> ActionPermit<'a, T> {
+    async fn perform(self) {
+        core::future::ready(()).await
+    }
+}
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
new file mode 100644
index 00000000000..b189b4e73f4
--- /dev/null
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
@@ -0,0 +1,281 @@
+- // MIR for `run2::{closure#0}` before Inline
++ // MIR for `run2::{closure#0}` after Inline
+  
+  fn run2::{closure#0}(_1: {closure@$DIR/inline_coroutine_body.rs:13:9: 13:11}) -> () {
+      debug permit => (_1.0: ActionPermit<'_, T>);
+      debug ctx => (*(_1.1: &mut std::task::Context<'_>));
+      let mut _0: ();
+      let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let mut _3: ActionPermit<'_, T>;
+      let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let _6: ();
+      let mut _7: std::task::Poll<()>;
+      let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+      let mut _9: &mut std::task::Context<'_>;
+      let mut _10: &mut std::task::Context<'_>;
+      scope 1 {
+          debug fut => _2;
+          let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+          scope 2 {
+              debug fut => _4;
+              scope 4 {
+              }
++             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++                 debug _task_context => _31;
++                 debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>);
++                 let _11: ActionPermit<'_, T>;
++                 let mut _12: std::future::Ready<()>;
++                 let mut _13: std::future::Ready<()>;
++                 let mut _14: ();
++                 let mut _16: ();
++                 let _17: ();
++                 let mut _18: std::task::Poll<()>;
++                 let mut _19: std::pin::Pin<&mut std::future::Ready<()>>;
++                 let mut _20: &mut std::future::Ready<()>;
++                 let mut _21: &mut std::future::Ready<()>;
++                 let mut _22: &mut std::task::Context<'_>;
++                 let mut _23: &mut std::task::Context<'_>;
++                 let mut _24: &mut std::task::Context<'_>;
++                 let mut _25: isize;
++                 let mut _27: !;
++                 let mut _28: &mut std::task::Context<'_>;
++                 let mut _29: ();
++                 let mut _30: ();
++                 let mut _31: &mut std::task::Context<'_>;
++                 let mut _32: u32;
++                 let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 scope 8 {
++                     debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>);
++                     let mut _15: std::future::Ready<()>;
++                     scope 9 {
++                         debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>);
++                         let _26: ();
++                         scope 10 {
++                         }
++                         scope 11 {
++                             debug result => _26;
++                         }
++                     }
++                     scope 12 (inlined ready::<()>) {
++                         debug t => _14;
++                         let mut _41: std::option::Option<()>;
++                     }
++                 }
++             }
+          }
+          scope 3 {
++             scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) {
++                 debug pointer => _5;
++             }
+          }
+      }
++     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++         debug self => _3;
++     }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = move (_1.0: ActionPermit<'_, T>);
+-         _2 = ActionPermit::<'_, T>::perform(move _3) -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
++         _2 = {coroutine@$DIR/inline_coroutine_body.rs:25:28: 27:6 (#0)} { self: move _3 };
+          StorageDead(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = &mut _2;
+-         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind unreachable];
+-     }
+- 
+-     bb2: {
++         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 };
+          StorageDead(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = move _4;
+          StorageLive(_9);
+          _10 = deref_copy (_1.1: &mut std::task::Context<'_>);
+          _9 = &mut (*_10);
+-         _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable];
++         StorageLive(_11);
++         StorageLive(_15);
++         StorageLive(_16);
++         StorageLive(_25);
++         StorageLive(_27);
++         StorageLive(_30);
++         StorageLive(_31);
++         StorageLive(_32);
++         StorageLive(_33);
++         StorageLive(_34);
++         StorageLive(_35);
++         StorageLive(_36);
++         StorageLive(_37);
++         StorageLive(_38);
++         StorageLive(_39);
++         StorageLive(_40);
++         _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _32 = discriminant((*_33));
++         switchInt(move _32) -> [0: bb3, 1: bb13, 3: bb12, otherwise: bb8];
+      }
+  
+-     bb3: {
++     bb1: {
++         StorageDead(_2);
++         return;
++     }
++ 
++     bb2: {
++         StorageDead(_40);
++         StorageDead(_39);
++         StorageDead(_38);
++         StorageDead(_37);
++         StorageDead(_36);
++         StorageDead(_35);
++         StorageDead(_34);
++         StorageDead(_33);
++         StorageDead(_32);
++         StorageDead(_31);
++         StorageDead(_30);
++         StorageDead(_27);
++         StorageDead(_25);
++         StorageDead(_16);
++         StorageDead(_15);
++         StorageDead(_11);
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageDead(_7);
+          _6 = const ();
+          StorageDead(_6);
+          _0 = const ();
+          StorageDead(_4);
+-         drop(_2) -> [return: bb4, unwind unreachable];
++         drop(_2) -> [return: bb1, unwind unreachable];
+      }
+  
++     bb3: {
++         _31 = move _9;
++         _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>);
++         StorageLive(_12);
++         StorageLive(_13);
++         StorageLive(_14);
++         _14 = ();
++         StorageLive(_41);
++         _41 = Option::<()>::Some(_14);
++         _13 = std::future::Ready::<()>(move _41);
++         StorageDead(_41);
++         StorageDead(_14);
++         _12 = <std::future::Ready<()> as IntoFuture>::into_future(move _13) -> [return: bb4, unwind unreachable];
++     }
++ 
+      bb4: {
+-         StorageDead(_2);
+-         return;
++         StorageDead(_13);
++         _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_36) as variant#3).1: std::future::Ready<()>) = move _12;
++         goto -> bb5;
++     }
++ 
++     bb5: {
++         StorageLive(_17);
++         StorageLive(_18);
++         StorageLive(_19);
++         StorageLive(_20);
++         StorageLive(_21);
++         _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
++         _20 = &mut (*_21);
++         _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb6, unwind unreachable];
++     }
++ 
++     bb6: {
++         StorageDead(_20);
++         StorageLive(_22);
++         StorageLive(_23);
++         StorageLive(_24);
++         _24 = _31;
++         _23 = move _24;
++         _22 = &mut (*_23);
++         StorageDead(_24);
++         _18 = <std::future::Ready<()> as Future>::poll(move _19, move _22) -> [return: bb7, unwind unreachable];
++     }
++ 
++     bb7: {
++         StorageDead(_22);
++         StorageDead(_19);
++         _25 = discriminant(_18);
++         switchInt(move _25) -> [0: bb10, 1: bb9, otherwise: bb8];
++     }
++ 
++     bb8: {
++         unreachable;
++     }
++ 
++     bb9: {
++         _17 = const ();
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageLive(_28);
++         StorageLive(_29);
++         _29 = ();
++         _7 = Poll::<()>::Pending;
++         StorageDead(_12);
++         StorageDead(_28);
++         StorageDead(_29);
++         _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_38)) = 3;
++         goto -> bb2;
++     }
++ 
++     bb10: {
++         StorageLive(_26);
++         _26 = ((_18 as Ready).0: ());
++         _30 = _26;
++         StorageDead(_26);
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageDead(_12);
++         _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb11, unwind unreachable];
++     }
++ 
++     bb11: {
++         _7 = Poll::<()>::Ready(move _30);
++         _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_40)) = 1;
++         goto -> bb2;
++     }
++ 
++     bb12: {
++         StorageLive(_12);
++         StorageLive(_28);
++         StorageLive(_29);
++         _28 = move _9;
++         StorageDead(_29);
++         _31 = move _28;
++         StorageDead(_28);
++         _16 = const ();
++         goto -> bb5;
++     }
++ 
++     bb13: {
++         assert(const false, "`async fn` resumed after completion") -> [success: bb13, unwind unreachable];
+      }
+  }
+  
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..ed18c0a3adb
--- /dev/null
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
@@ -0,0 +1,341 @@
+- // MIR for `run2::{closure#0}` before Inline
++ // MIR for `run2::{closure#0}` after Inline
+  
+  fn run2::{closure#0}(_1: {closure@$DIR/inline_coroutine_body.rs:13:9: 13:11}) -> () {
+      debug permit => (_1.0: ActionPermit<'_, T>);
+      debug ctx => (*(_1.1: &mut std::task::Context<'_>));
+      let mut _0: ();
+      let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let mut _3: ActionPermit<'_, T>;
+      let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let _6: ();
+      let mut _7: std::task::Poll<()>;
+      let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+      let mut _9: &mut std::task::Context<'_>;
+      let mut _10: &mut std::task::Context<'_>;
+      scope 1 {
+          debug fut => _2;
+          let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+          scope 2 {
+              debug fut => _4;
+              scope 4 {
+              }
++             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++                 debug _task_context => _31;
++                 debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>);
++                 let _11: ActionPermit<'_, T>;
++                 let mut _12: std::future::Ready<()>;
++                 let mut _13: std::future::Ready<()>;
++                 let mut _14: ();
++                 let mut _16: ();
++                 let _17: ();
++                 let mut _18: std::task::Poll<()>;
++                 let mut _19: std::pin::Pin<&mut std::future::Ready<()>>;
++                 let mut _20: &mut std::future::Ready<()>;
++                 let mut _21: &mut std::future::Ready<()>;
++                 let mut _22: &mut std::task::Context<'_>;
++                 let mut _23: &mut std::task::Context<'_>;
++                 let mut _24: &mut std::task::Context<'_>;
++                 let mut _25: isize;
++                 let mut _27: !;
++                 let mut _28: &mut std::task::Context<'_>;
++                 let mut _29: ();
++                 let mut _30: ();
++                 let mut _31: &mut std::task::Context<'_>;
++                 let mut _32: u32;
++                 let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _41: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _42: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 scope 8 {
++                     debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>);
++                     let mut _15: std::future::Ready<()>;
++                     scope 9 {
++                         debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>);
++                         let _26: ();
++                         scope 10 {
++                         }
++                         scope 11 {
++                             debug result => _26;
++                         }
++                     }
++                     scope 12 (inlined ready::<()>) {
++                         debug t => _14;
++                         let mut _43: std::option::Option<()>;
++                     }
++                 }
++             }
+          }
+          scope 3 {
++             scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) {
++                 debug pointer => _5;
++             }
+          }
+      }
++     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++         debug self => _3;
++     }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = move (_1.0: ActionPermit<'_, T>);
+-         _2 = ActionPermit::<'_, T>::perform(move _3) -> [return: bb1, unwind: bb6];
+-     }
+- 
+-     bb1: {
++         _2 = {coroutine@$DIR/inline_coroutine_body.rs:25:28: 27:6 (#0)} { self: move _3 };
+          StorageDead(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = &mut _2;
+-         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind: bb5];
+-     }
+- 
+-     bb2: {
++         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 };
+          StorageDead(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = move _4;
+          StorageLive(_9);
+          _10 = deref_copy (_1.1: &mut std::task::Context<'_>);
+          _9 = &mut (*_10);
+-         _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5];
++         StorageLive(_11);
++         StorageLive(_15);
++         StorageLive(_16);
++         StorageLive(_25);
++         StorageLive(_27);
++         StorageLive(_30);
++         StorageLive(_31);
++         StorageLive(_32);
++         StorageLive(_33);
++         StorageLive(_34);
++         StorageLive(_35);
++         StorageLive(_36);
++         StorageLive(_37);
++         StorageLive(_38);
++         StorageLive(_39);
++         StorageLive(_40);
++         StorageLive(_41);
++         StorageLive(_42);
++         _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _32 = discriminant((*_33));
++         switchInt(move _32) -> [0: bb5, 1: bb22, 2: bb21, 3: bb20, otherwise: bb10];
+      }
+  
+-     bb3: {
++     bb1: {
++         StorageDead(_2);
++         return;
++     }
++ 
++     bb2 (cleanup): {
++         drop(_2) -> [return: bb3, unwind terminate(cleanup)];
++     }
++ 
++     bb3 (cleanup): {
++         resume;
++     }
++ 
++     bb4: {
++         StorageDead(_42);
++         StorageDead(_41);
++         StorageDead(_40);
++         StorageDead(_39);
++         StorageDead(_38);
++         StorageDead(_37);
++         StorageDead(_36);
++         StorageDead(_35);
++         StorageDead(_34);
++         StorageDead(_33);
++         StorageDead(_32);
++         StorageDead(_31);
++         StorageDead(_30);
++         StorageDead(_27);
++         StorageDead(_25);
++         StorageDead(_16);
++         StorageDead(_15);
++         StorageDead(_11);
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageDead(_7);
+          _6 = const ();
+          StorageDead(_6);
+          _0 = const ();
+          StorageDead(_4);
+-         drop(_2) -> [return: bb4, unwind: bb6];
++         drop(_2) -> [return: bb1, unwind: bb3];
+      }
+  
+-     bb4: {
+-         StorageDead(_2);
+-         return;
++     bb5: {
++         _31 = move _9;
++         _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>);
++         StorageLive(_12);
++         StorageLive(_13);
++         StorageLive(_14);
++         _14 = ();
++         StorageLive(_43);
++         _43 = Option::<()>::Some(_14);
++         _13 = std::future::Ready::<()>(move _43);
++         StorageDead(_43);
++         StorageDead(_14);
++         _12 = <std::future::Ready<()> as IntoFuture>::into_future(move _13) -> [return: bb6, unwind: bb17];
+      }
+  
+-     bb5 (cleanup): {
+-         drop(_2) -> [return: bb6, unwind terminate(cleanup)];
++     bb6: {
++         StorageDead(_13);
++         _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_36) as variant#3).1: std::future::Ready<()>) = move _12;
++         goto -> bb7;
+      }
+  
+-     bb6 (cleanup): {
+-         resume;
++     bb7: {
++         StorageLive(_17);
++         StorageLive(_18);
++         StorageLive(_19);
++         StorageLive(_20);
++         StorageLive(_21);
++         _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
++         _20 = &mut (*_21);
++         _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb8, unwind: bb15];
++     }
++ 
++     bb8: {
++         StorageDead(_20);
++         StorageLive(_22);
++         StorageLive(_23);
++         StorageLive(_24);
++         _24 = _31;
++         _23 = move _24;
++         _22 = &mut (*_23);
++         StorageDead(_24);
++         _18 = <std::future::Ready<()> as Future>::poll(move _19, move _22) -> [return: bb9, unwind: bb14];
++     }
++ 
++     bb9: {
++         StorageDead(_22);
++         StorageDead(_19);
++         _25 = discriminant(_18);
++         switchInt(move _25) -> [0: bb12, 1: bb11, otherwise: bb10];
++     }
++ 
++     bb10: {
++         unreachable;
++     }
++ 
++     bb11: {
++         _17 = const ();
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageLive(_28);
++         StorageLive(_29);
++         _29 = ();
++         _7 = Poll::<()>::Pending;
++         StorageDead(_12);
++         StorageDead(_28);
++         StorageDead(_29);
++         _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_38)) = 3;
++         goto -> bb4;
++     }
++ 
++     bb12: {
++         StorageLive(_26);
++         _26 = ((_18 as Ready).0: ());
++         _30 = _26;
++         StorageDead(_26);
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageDead(_12);
++         _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb13, unwind: bb19];
++     }
++ 
++     bb13: {
++         _7 = Poll::<()>::Ready(move _30);
++         _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_40)) = 1;
++         goto -> bb4;
++     }
++ 
++     bb14 (cleanup): {
++         StorageDead(_22);
++         StorageDead(_19);
++         StorageDead(_23);
++         goto -> bb16;
++     }
++ 
++     bb15 (cleanup): {
++         StorageDead(_20);
++         StorageDead(_19);
++         goto -> bb16;
++     }
++ 
++     bb16 (cleanup): {
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         goto -> bb18;
++     }
++ 
++     bb17 (cleanup): {
++         StorageDead(_13);
++         goto -> bb18;
++     }
++ 
++     bb18 (cleanup): {
++         StorageDead(_12);
++         _41 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         drop((((*_41) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb19, unwind terminate(cleanup)];
++     }
++ 
++     bb19 (cleanup): {
++         _42 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_42)) = 2;
++         goto -> bb2;
++     }
++ 
++     bb20: {
++         StorageLive(_12);
++         StorageLive(_28);
++         StorageLive(_29);
++         _28 = move _9;
++         StorageDead(_29);
++         _31 = move _28;
++         StorageDead(_28);
++         _16 = const ();
++         goto -> bb7;
++     }
++ 
++     bb21: {
++         assert(const false, "`async fn` resumed after panicking") -> [success: bb21, unwind: bb2];
++     }
++ 
++     bb22: {
++         assert(const false, "`async fn` resumed after completion") -> [success: bb22, unwind: bb2];
+      }
+  }
+  
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs b/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs
index 67540676f4a..561bafa9651 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0
-//@ ignore-debug: standard library debug assertions add a panic that breaks this optimization
 
 #![crate_type = "lib"]
 
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
index 0597e453e22..455e4ba7244 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
@@ -9,6 +9,10 @@ fn ub_if_b(_1: Thing) -> Thing {
         let _4: ();
         scope 2 {
         }
+        scope 3 (inlined core::ub_checks::check_language_ub) {
+            scope 4 (inlined core::ub_checks::check_language_ub::runtime) {
+            }
+        }
     }
 
     bb0: {
@@ -23,7 +27,7 @@ fn ub_if_b(_1: Thing) -> Thing {
 
     bb2: {
         StorageLive(_3);
-        _3 = UbCheck(LanguageUb);
+        _3 = UbChecks();
         assume(_3);
         _4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
     }
diff --git a/tests/mir-opt/pre-codegen/mem_replace.rs b/tests/mir-opt/pre-codegen/mem_replace.rs
index 9cb3a839956..a68fe31f609 100644
--- a/tests/mir-opt/pre-codegen/mem_replace.rs
+++ b/tests/mir-opt/pre-codegen/mem_replace.rs
@@ -1,6 +1,6 @@
 // skip-filecheck
 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir
-//@ ignore-debug the standard library debug assertions leak into this test
+//@ ignore-debug: precondition checks on ptr::read/write are under cfg(debug_assertions)
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs
index 1d977ee9214..c9dd72d8be2 100644
--- a/tests/mir-opt/pre-codegen/slice_index.rs
+++ b/tests/mir-opt/pre-codegen/slice_index.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
-//@ ignore-debug the standard library debug assertions leak into this test
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/pre-codegen/slice_iter.rs b/tests/mir-opt/pre-codegen/slice_iter.rs
index 0fbd3706544..86f37ca4d13 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.rs
+++ b/tests/mir-opt/pre-codegen/slice_iter.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
-//@ ignore-debug the standard library debug assertions leak into this test
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![crate_type = "lib"]
diff --git a/tests/run-make/rustdoc-test-args/foo.rs b/tests/run-make/rustdoc-test-args/foo.rs
new file mode 100644
index 00000000000..51d17849fd7
--- /dev/null
+++ b/tests/run-make/rustdoc-test-args/foo.rs
@@ -0,0 +1,3 @@
+//! ```
+//! let x = 12;
+//! ```
diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs
new file mode 100644
index 00000000000..808d13928eb
--- /dev/null
+++ b/tests/run-make/rustdoc-test-args/rmake.rs
@@ -0,0 +1,18 @@
+extern crate run_make_support;
+
+use run_make_support::{out_dir, rustdoc};
+use std::{fs, iter};
+use std::path::Path;
+
+fn generate_a_lot_of_cfgs(path: &Path) {
+    let content = iter::repeat("--cfg=a\n").take(100_000).collect::<String>();
+    fs::write(path, content.as_bytes()).expect("failed to create args file");
+}
+
+fn main() {
+    let arg_file = out_dir().join("args");
+    generate_a_lot_of_cfgs(&arg_file);
+
+    let arg_file = format!("@{}", arg_file.display());
+    rustdoc().arg("--test").arg(&arg_file).arg("foo.rs").run();
+}
diff --git a/tests/ui/asm/aarch64/type-check-3.stderr b/tests/ui/asm/aarch64/type-check-3.stderr
index f710df2dcde..9e37bb4c203 100644
--- a/tests/ui/asm/aarch64/type-check-3.stderr
+++ b/tests/ui/asm/aarch64/type-check-3.stderr
@@ -4,8 +4,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0u8);
    |               ^^           --- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 warning: formatting may not be suitable for sub-register argument
@@ -14,8 +14,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0u16);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:52:15
@@ -23,8 +23,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0i32);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:54:15
@@ -32,8 +32,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0f32);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:57:15
@@ -41,8 +41,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0i16);
    |               ^^            ---- for this argument
    |
-   = help: use `{0:h}` to have the register formatted as `h0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:h}` to have the register formatted as `h0` (for 16-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:59:15
@@ -50,8 +50,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0f32);
    |               ^^            ---- for this argument
    |
-   = help: use `{0:s}` to have the register formatted as `s0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:s}` to have the register formatted as `s0` (for 32-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:61:15
@@ -59,8 +59,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0f64);
    |               ^^            ---- for this argument
    |
-   = help: use `{0:d}` to have the register formatted as `d0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:63:15
@@ -68,8 +68,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg_low16) 0f64);
    |               ^^                  ---- for this argument
    |
-   = help: use `{0:d}` to have the register formatted as `d0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:66:15
@@ -77,8 +77,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:68:15
@@ -86,8 +86,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0:x}", in(reg) 0i16);
    |               ^^^                 ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 error: type `i128` cannot be used with this register class
   --> $DIR/type-check-3.rs:73:28
diff --git a/tests/ui/asm/bad-template.aarch64.stderr b/tests/ui/asm/bad-template.aarch64.stderr
index b18946d7c6d..5023cf317d7 100644
--- a/tests/ui/asm/bad-template.aarch64.stderr
+++ b/tests/ui/asm/bad-template.aarch64.stderr
@@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 error: aborting due to 21 previous errors; 1 warning emitted
diff --git a/tests/ui/asm/bad-template.x86_64.stderr b/tests/ui/asm/bad-template.x86_64.stderr
index 2f584c30a32..1b9775636f5 100644
--- a/tests/ui/asm/bad-template.x86_64.stderr
+++ b/tests/ui/asm/bad-template.x86_64.stderr
@@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
-   = help: use `{0:e}` to have the register formatted as `eax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 error: aborting due to 21 previous errors; 1 warning emitted
diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr
index 1baf50ff6e0..34bfcd71cac 100644
--- a/tests/ui/asm/x86_64/type-check-3.stderr
+++ b/tests/ui/asm/x86_64/type-check-3.stderr
@@ -44,8 +44,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
-   = help: use `{0:x}` to have the register formatted as `ax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 warning: formatting may not be suitable for sub-register argument
@@ -54,8 +54,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0:x}", in(reg) 0i16);
    |               ^^^                 ---- for this argument
    |
-   = help: use `{0:x}` to have the register formatted as `ax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:38:15
@@ -63,8 +63,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0i32);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:e}` to have the register formatted as `eax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:41:15
@@ -72,8 +72,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(ymm_reg) 0i64);
    |               ^^               ---- for this argument
    |
-   = help: use `{0:x}` to have the register formatted as `xmm0`
-   = help: or use `{0:y}` to keep the default formatting of `ymm0`
+   = help: use `{0:x}` to have the register formatted as `xmm0` (for 128-bit values)
+   = help: or use `{0:y}` to keep the default formatting of `ymm0` (for 256-bit values)
 
 error: type `i8` cannot be used with this register class
   --> $DIR/type-check-3.rs:52:28
diff --git a/tests/ui/associated-type-bounds/auxiliary/implied-predicates.rs b/tests/ui/associated-type-bounds/auxiliary/implied-predicates.rs
new file mode 100644
index 00000000000..fe74c64fbe2
--- /dev/null
+++ b/tests/ui/associated-type-bounds/auxiliary/implied-predicates.rs
@@ -0,0 +1,7 @@
+pub trait Bar: Super<SuperAssoc: Bound> {}
+
+pub trait Super {
+    type SuperAssoc;
+}
+
+pub trait Bound {}
diff --git a/tests/ui/associated-type-bounds/implied-predicates.rs b/tests/ui/associated-type-bounds/implied-predicates.rs
new file mode 100644
index 00000000000..e97d7a396c4
--- /dev/null
+++ b/tests/ui/associated-type-bounds/implied-predicates.rs
@@ -0,0 +1,9 @@
+//@ aux-build:implied-predicates.rs
+//@ check-pass
+
+extern crate implied_predicates;
+use implied_predicates::Bar;
+
+fn bar<B: Bar>() {}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/resolution-failure-building-vtable-representation-ice-90691.rs b/tests/ui/associated-type-bounds/resolution-failure-building-vtable-representation-ice-90691.rs
new file mode 100644
index 00000000000..d3c13974127
--- /dev/null
+++ b/tests/ui/associated-type-bounds/resolution-failure-building-vtable-representation-ice-90691.rs
@@ -0,0 +1,42 @@
+// ICE #90691 Encountered error `Unimplemented` selecting  ...
+//@ build-pass
+// issue: rust-lang/rust#90691
+
+trait TError: std::fmt::Debug {}
+impl TError for () {}
+
+trait SuperTrait {
+    type Error;
+}
+
+trait Trait: SuperTrait<Error: TError> {}
+
+impl<T> Trait for T
+where
+    T: SuperTrait,
+    <T as SuperTrait>::Error: TError,
+{
+}
+
+struct SomeTrait<S>(S);
+struct BoxedTrait(Box<dyn Trait<Error = ()>>);
+
+impl<S: 'static> From<SomeTrait<S>> for BoxedTrait {
+    fn from(other: SomeTrait<S>) -> Self {
+        Self(Box::new(other))
+    }
+}
+
+impl<S> SuperTrait for SomeTrait<S> {
+    type Error = ();
+}
+
+impl From<()> for BoxedTrait {
+    fn from(c: ()) -> Self {
+        Self::from(SomeTrait(c))
+    }
+}
+
+fn main() {
+    let _: BoxedTrait = ().into();
+}
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
index 47b39e5246d..d6fb643702c 100644
--- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
+++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
@@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2}`:
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3077 bytes
-print-type-size         local `.__awaitee`: 3077 bytes
+print-type-size         local `.__awaitee`: 3077 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes
@@ -19,19 +19,19 @@ print-type-size     variant `Suspend0`: 2052 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1 bytes
 print-type-size         local `.fut`: 1025 bytes, alignment: 1 bytes
-print-type-size         local `..coroutine_field4`: 1 bytes
-print-type-size         local `.__awaitee`: 1 bytes
+print-type-size         local `..coroutine_field4`: 1 bytes, type: bool
+print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
 print-type-size     variant `Suspend1`: 3076 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1026 bytes
-print-type-size         local `..coroutine_field4`: 1 bytes, alignment: 1 bytes
-print-type-size         local `.__awaitee`: 1025 bytes
+print-type-size         local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool
+print-type-size         local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}
 print-type-size     variant `Suspend2`: 2052 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1 bytes
 print-type-size         local `.fut`: 1025 bytes, alignment: 1 bytes
-print-type-size         local `..coroutine_field4`: 1 bytes
-print-type-size         local `.__awaitee`: 1 bytes
+print-type-size         local `..coroutine_field4`: 1 bytes, type: bool
+print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
 print-type-size     variant `Returned`: 1025 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 1025 bytes
diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout
index 005460df626..589df102af4 100644
--- a/tests/ui/async-await/future-sizes/large-arg.stdout
+++ b/tests/ui/async-await/future-sizes/large-arg.stdout
@@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/large-arg.rs:6:21: 8:2}`: 3076 bytes,
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3075 bytes
-print-type-size         local `.__awaitee`: 3075 bytes
+print-type-size         local `.__awaitee`: 3075 bytes, type: {async fn body@$DIR/large-arg.rs:10:30: 12:2}
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes
@@ -17,7 +17,7 @@ print-type-size     variant `Unresumed`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Suspend0`: 3074 bytes
 print-type-size         upvar `.t`: 1024 bytes
-print-type-size         local `.__awaitee`: 2050 bytes
+print-type-size         local `.__awaitee`: 2050 bytes, type: {async fn body@$DIR/large-arg.rs:13:26: 15:2}
 print-type-size     variant `Returned`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
@@ -34,7 +34,7 @@ print-type-size     variant `Unresumed`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Suspend0`: 2049 bytes
 print-type-size         upvar `.t`: 1024 bytes
-print-type-size         local `.__awaitee`: 1025 bytes
+print-type-size         local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/large-arg.rs:16:26: 18:2}
 print-type-size     variant `Returned`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs
new file mode 100644
index 00000000000..b9e729bff62
--- /dev/null
+++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs
@@ -0,0 +1,26 @@
+// issue: rust-lang/rust#104779
+// ICE region infer, IndexMap: key not found
+
+struct Inv<'a>(&'a mut &'a ());
+enum Foo<T> {
+    Bar,
+    Var(T),
+}
+type Subtype = Foo<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>;
+type Supertype = Foo<for<'a> fn(Inv<'a>, Inv<'a>)>;
+
+fn foo() -> impl Sized {
+//~^ WARN function cannot return without recursing
+    loop {
+        match foo() {
+        //~^ ERROR higher-ranked subtype error
+        //~^^ ERROR higher-ranked subtype error
+            Subtype::Bar => (),
+            //~^ ERROR higher-ranked subtype error
+            //~^^ ERROR higher-ranked subtype error
+            Supertype::Var(x) => {}
+        }
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr
new file mode 100644
index 00000000000..887cb14a769
--- /dev/null
+++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr
@@ -0,0 +1,42 @@
+warning: function cannot return without recursing
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:12:1
+   |
+LL | fn foo() -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |         match foo() {
+   |               ----- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15
+   |
+LL |         match foo() {
+   |               ^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15
+   |
+LL |         match foo() {
+   |               ^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13
+   |
+LL |             Subtype::Bar => (),
+   |             ^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13
+   |
+LL |             Subtype::Bar => (),
+   |             ^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
diff --git a/tests/ui/const-generics/generic_const_exprs/failed-to-normalize-ice-issue-88421.rs b/tests/ui/const-generics/generic_const_exprs/failed-to-normalize-ice-issue-88421.rs
new file mode 100644
index 00000000000..3d41eeeff45
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/failed-to-normalize-ice-issue-88421.rs
@@ -0,0 +1,36 @@
+//@ check-pass
+// issue: rust-lang/rust#88421
+#![feature(adt_const_params)]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+use std::ops::Index;
+
+pub struct CellPossibilities;
+
+pub enum CellState<const SQUARE_SIZE: usize> {
+    Empty(Option<CellPossibilities>),
+}
+
+pub struct Sudoku<const SQUARE_SIZE: usize>;
+
+impl<const SQUARE_SIZE: usize> Sudoku<SQUARE_SIZE>where
+    [CellState<SQUARE_SIZE>; SQUARE_SIZE * SQUARE_SIZE]: Sized,
+{
+    pub fn random() {
+        let CellState::Empty(_) = Self[()];
+    }
+}
+
+impl<const SQUARE_SIZE: usize> Index<()> for Sudoku<SQUARE_SIZE>
+where
+    [CellState<SQUARE_SIZE>; SQUARE_SIZE * SQUARE_SIZE]: Sized,
+{
+    type Output = CellState<SQUARE_SIZE>;
+
+    fn index(&self, _: ()) -> &Self::Output {
+        todo!()
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs
new file mode 100644
index 00000000000..ed5ba32b621
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs
@@ -0,0 +1,57 @@
+// issue: rust-lang/rust#106423
+// ICE collection encountered polymorphic constant: UnevaluatedConst {..}
+//@ edition:2021
+//@ check-pass
+
+#![feature(generic_const_exprs, generic_arg_infer)]
+#![allow(incomplete_features)]
+#![allow(unused)]
+
+use core::mem::MaybeUninit;
+
+pub struct Arr<T, const N: usize> {
+    v: [MaybeUninit<T>; N],
+}
+
+impl<T, const N: usize> Arr<T, N> {
+    const ELEM: MaybeUninit<T> = MaybeUninit::uninit();
+    const INIT: [MaybeUninit<T>; N] = [Self::ELEM; N]; // important for optimization of `new`
+
+    fn new() -> Self {
+        Arr { v: Self::INIT }
+    }
+}
+
+pub struct BaFormatFilter<const N: usize> {}
+
+pub enum DigitalFilter<const N: usize>
+where
+    [(); N * 2 + 1]: Sized,
+    [(); N * 2]: Sized,
+{
+    Ba(BaFormatFilter<{ N * 2 + 1 }>),
+}
+
+pub fn iirfilter_st_copy<const N: usize, const M: usize>(_: [f32; M]) -> DigitalFilter<N>
+where
+    [(); N * 2 + 1]: Sized,
+    [(); N * 2]: Sized,
+{
+    let zpk = zpk2tf_st(&Arr::<f32, { N * 2 }>::new(), &Arr::<f32, { N * 2 }>::new());
+    DigitalFilter::Ba(zpk)
+}
+
+pub fn zpk2tf_st<const N: usize>(
+    _z: &Arr<f32, N>,
+    _p: &Arr<f32, N>,
+) -> BaFormatFilter<{ N + 1 }>
+where
+    [(); N + 1]: Sized,
+{
+    BaFormatFilter {}
+}
+
+
+fn main() {
+    iirfilter_st_copy::<4, 2>([10., 50.,]);
+}
diff --git a/tests/ui/consts/ice-bad-input-type-for-cast-83056.rs b/tests/ui/consts/ice-bad-input-type-for-cast-83056.rs
new file mode 100644
index 00000000000..1a22dc2b549
--- /dev/null
+++ b/tests/ui/consts/ice-bad-input-type-for-cast-83056.rs
@@ -0,0 +1,7 @@
+// #83056 ICE "bad input type for cast"
+// issue: rust-lang/rust#83056
+
+struct S([bool; f as usize]);
+fn f() -> T {}
+//~^ ERROR cannot find type `T` in this scope
+pub fn main() {}
diff --git a/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr b/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr
new file mode 100644
index 00000000000..115f1688520
--- /dev/null
+++ b/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr
@@ -0,0 +1,20 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/ice-bad-input-type-for-cast-83056.rs:5:11
+   |
+LL | struct S([bool; f as usize]);
+   | ----------------------------- similarly named struct `S` defined here
+LL | fn f() -> T {}
+   |           ^
+   |
+help: a struct with a similar name exists
+   |
+LL | fn f() -> S {}
+   |           ~
+help: you might be missing a type parameter
+   |
+LL | fn f<T>() -> T {}
+   |     +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr
index 3e3e8e976be..9e0506e7e38 100644
--- a/tests/ui/consts/missing_span_in_backtrace.stderr
+++ b/tests/ui/consts/missing_span_in_backtrace.stderr
@@ -5,8 +5,6 @@ error[E0080]: evaluation of constant value failed
    |
 note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `mem::swap_simple::<MaybeUninit<MaybeUninit<u8>>>`
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 note: inside `std::ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
diff --git a/tests/ui/drop/norm-ice-106444.rs b/tests/ui/drop/norm-ice-106444.rs
new file mode 100644
index 00000000000..b248bc73bbe
--- /dev/null
+++ b/tests/ui/drop/norm-ice-106444.rs
@@ -0,0 +1,16 @@
+// issue: rust-lang/rust#106444
+// ICE failed to normalize
+//@ compile-flags: -Zmir-opt-level=3
+//@ check-pass
+
+#![crate_type="lib"]
+
+pub trait A {
+    type B;
+}
+
+pub struct S<T: A>(T::B);
+
+pub fn foo<T: A>(p: *mut S<T>) {
+    unsafe { core::ptr::drop_in_place(p) };
+}
diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.rs b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.rs
new file mode 100644
index 00000000000..bba7190d43d
--- /dev/null
+++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.rs
@@ -0,0 +1,16 @@
+// test for ICE when casting extern "C" fn when it has a non-FFI-safe argument
+// issue: rust-lang/rust#52334
+//@ check-pass
+//@ normalize-stderr-test "\[i8\]" -> "[i8 or u8 (arch dependant)]"
+//@ normalize-stderr-test "\[u8\]" -> "[i8 or u8 (arch dependant)]"
+
+type Foo = extern "C" fn(::std::ffi::CStr);
+//~^ WARN `extern` fn uses type
+extern "C" {
+    fn meh(blah: Foo);
+    //~^ WARN `extern` block uses type
+}
+
+fn main() {
+    meh as usize;
+}
diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
new file mode 100644
index 00000000000..83492988479
--- /dev/null
+++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
@@ -0,0 +1,22 @@
+warning: `extern` fn uses type `[i8 or u8 (arch dependant)]`, which is not FFI-safe
+  --> $DIR/extern-C-non-FFI-safe-arg-ice-52334.rs:7:12
+   |
+LL | type Foo = extern "C" fn(::std::ffi::CStr);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
+   = note: `#[warn(improper_ctypes_definitions)]` on by default
+
+warning: `extern` block uses type `[i8 or u8 (arch dependant)]`, which is not FFI-safe
+  --> $DIR/extern-C-non-FFI-safe-arg-ice-52334.rs:10:18
+   |
+LL |     fn meh(blah: Foo);
+   |                  ^^^ not FFI-safe
+   |
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
+   = note: `#[warn(improper_ctypes)]` on by default
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/extern/extern-C-str-arg-ice-80125.rs b/tests/ui/extern/extern-C-str-arg-ice-80125.rs
new file mode 100644
index 00000000000..0908d6199ef
--- /dev/null
+++ b/tests/ui/extern/extern-C-str-arg-ice-80125.rs
@@ -0,0 +1,15 @@
+// issue: rust-lang/rust#80125
+//@ check-pass
+type ExternCallback = extern "C" fn(*const u8, u32, str);
+//~^ WARN `extern` fn uses type `str`, which is not FFI-safe
+
+pub struct Struct(ExternCallback);
+
+#[no_mangle]
+pub extern "C" fn register_something(bind: ExternCallback) -> Struct {
+//~^ WARN `extern` fn uses type `str`, which is not FFI-safe
+//~^^ WARN `extern` fn uses type `Struct`, which is not FFI-safe
+    Struct(bind)
+}
+
+fn main() {}
diff --git a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
new file mode 100644
index 00000000000..ebd6cec6ecd
--- /dev/null
+++ b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
@@ -0,0 +1,35 @@
+warning: `extern` fn uses type `str`, which is not FFI-safe
+  --> $DIR/extern-C-str-arg-ice-80125.rs:3:23
+   |
+LL | type ExternCallback = extern "C" fn(*const u8, u32, str);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
+   = note: `#[warn(improper_ctypes_definitions)]` on by default
+
+warning: `extern` fn uses type `str`, which is not FFI-safe
+  --> $DIR/extern-C-str-arg-ice-80125.rs:9:44
+   |
+LL | pub extern "C" fn register_something(bind: ExternCallback) -> Struct {
+   |                                            ^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
+
+warning: `extern` fn uses type `Struct`, which is not FFI-safe
+  --> $DIR/extern-C-str-arg-ice-80125.rs:9:63
+   |
+LL | pub extern "C" fn register_something(bind: ExternCallback) -> Struct {
+   |                                                               ^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+note: the type is defined here
+  --> $DIR/extern-C-str-arg-ice-80125.rs:6:1
+   |
+LL | pub struct Struct(ExternCallback);
+   | ^^^^^^^^^^^^^^^^^
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs
new file mode 100644
index 00000000000..8df24702811
--- /dev/null
+++ b/tests/ui/higher-ranked/structually-relate-aliases.rs
@@ -0,0 +1,17 @@
+// regression test for issue #121649.
+
+trait ToUnit<'a> {
+    type Unit;
+}
+
+trait Overlap<T> {}
+
+type Assoc<'a, T> = <T as ToUnit<'a>>::Unit;
+
+impl<T> Overlap<T> for T {}
+
+impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+//~^ ERROR 13:17: 13:49: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277]
+//~| ERROR 13:36: 13:48: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277]
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr
new file mode 100644
index 00000000000..59fab52b221
--- /dev/null
+++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr
@@ -0,0 +1,27 @@
+WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
+WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
+error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
+  --> $DIR/structually-relate-aliases.rs:13:36
+   |
+LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |                                    ^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |       ++++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
+  --> $DIR/structually-relate-aliases.rs:13:17
+   |
+LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |       ++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs
index 6f0dbd752b0..21e2fda1c3a 100644
--- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs
@@ -1,5 +1,4 @@
-struct Wrapper<'rom>(T);
-//~^ ERROR cannot find type `T` in this scope
+struct Wrapper<'rom>(&'rom ());
 
 trait Foo {
     fn bar() -> Wrapper<impl Sized>;
@@ -15,4 +14,18 @@ impl Foo for () {
     }
 }
 
+trait Bar {
+    fn foo() -> Wrapper<impl Sized>;
+    //~^ ERROR missing lifetime specifier
+    //~| ERROR struct takes 0 generic arguments but 1 generic argument was supplied
+}
+
+impl Bar for () {
+    fn foo() -> Wrapper<impl Sized> {
+        //~^ ERROR missing lifetime specifier
+        //~| ERROR struct takes 0 generic arguments but 1 generic argument was supplied
+        Wrapper(&())
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
index d30557c8a7b..d7fc40fa342 100644
--- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/opaque-and-lifetime-mismatch.rs:5:24
+  --> $DIR/opaque-and-lifetime-mismatch.rs:4:24
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
    |                        ^ expected named lifetime parameter
@@ -10,19 +10,32 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
 LL |     fn bar() -> Wrapper<'static, impl Sized>;
    |                         ++++++++
 
-error[E0412]: cannot find type `T` in this scope
-  --> $DIR/opaque-and-lifetime-mismatch.rs:1:22
+error[E0106]: missing lifetime specifier
+  --> $DIR/opaque-and-lifetime-mismatch.rs:18:24
+   |
+LL |     fn foo() -> Wrapper<impl Sized>;
+   |                        ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
+   |
+LL |     fn foo() -> Wrapper<'static, impl Sized>;
+   |                         ++++++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/opaque-and-lifetime-mismatch.rs:24:24
    |
-LL | struct Wrapper<'rom>(T);
-   |                      ^ not found in this scope
+LL |     fn foo() -> Wrapper<impl Sized> {
+   |                        ^ expected named lifetime parameter
    |
-help: you might be missing a type parameter
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
-LL | struct Wrapper<'rom, T>(T);
-   |                    +++
+LL |     fn foo() -> Wrapper<'static, impl Sized> {
+   |                         ++++++++
 
 error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/opaque-and-lifetime-mismatch.rs:5:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:4:17
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
    |                 ^^^^^^^ ---------- help: remove this generic argument
@@ -32,11 +45,25 @@ LL |     fn bar() -> Wrapper<impl Sized>;
 note: struct defined here, with 0 generic parameters
   --> $DIR/opaque-and-lifetime-mismatch.rs:1:8
    |
-LL | struct Wrapper<'rom>(T);
+LL | struct Wrapper<'rom>(&'rom ());
+   |        ^^^^^^^
+
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/opaque-and-lifetime-mismatch.rs:18:17
+   |
+LL |     fn foo() -> Wrapper<impl Sized>;
+   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 |
+   |                 expected 0 generic arguments
+   |
+note: struct defined here, with 0 generic parameters
+  --> $DIR/opaque-and-lifetime-mismatch.rs:1:8
+   |
+LL | struct Wrapper<'rom>(&'rom ());
    |        ^^^^^^^
 
 error[E0053]: method `bar` has an incompatible return type for trait
-  --> $DIR/opaque-and-lifetime-mismatch.rs:11:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:10:17
    |
 LL |     fn bar() -> i32 {
    |                 ^^^
@@ -45,7 +72,7 @@ LL |     fn bar() -> i32 {
    |                 return type in trait
 
 error[E0053]: method `bar` has an incompatible type for trait
-  --> $DIR/opaque-and-lifetime-mismatch.rs:11:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:10:17
    |
 LL |     fn bar() -> i32 {
    |                 ^^^
@@ -54,14 +81,28 @@ LL |     fn bar() -> i32 {
    |                 help: change the output type to match the trait: `Wrapper<'static>`
    |
 note: type in trait
-  --> $DIR/opaque-and-lifetime-mismatch.rs:5:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:4:17
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
    |                 ^^^^^^^^^^^^^^^^^^^
    = note: expected signature `fn() -> Wrapper<'static>`
               found signature `fn() -> i32`
 
-error: aborting due to 5 previous errors
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/opaque-and-lifetime-mismatch.rs:24:17
+   |
+LL |     fn foo() -> Wrapper<impl Sized> {
+   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 |
+   |                 expected 0 generic arguments
+   |
+note: struct defined here, with 0 generic parameters
+  --> $DIR/opaque-and-lifetime-mismatch.rs:1:8
+   |
+LL | struct Wrapper<'rom>(&'rom ());
+   |        ^^^^^^^
+
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0053, E0106, E0107, E0412.
+Some errors have detailed explanations: E0053, E0106, E0107.
 For more information about an error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/recursive-ice-101862.rs b/tests/ui/impl-trait/recursive-ice-101862.rs
new file mode 100644
index 00000000000..02f95fe5604
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-ice-101862.rs
@@ -0,0 +1,12 @@
+// issue: rust-lang/rust#101852
+// ICE opaque type with non-universal region substs
+
+pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
+//~^ WARN function cannot return without recursing
+    vec![].append(&mut ice(x.as_ref()));
+    //~^ ERROR expected generic type parameter, found `&str`
+
+    Vec::new()
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/recursive-ice-101862.stderr b/tests/ui/impl-trait/recursive-ice-101862.stderr
new file mode 100644
index 00000000000..f4148720c33
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-ice-101862.stderr
@@ -0,0 +1,24 @@
+warning: function cannot return without recursing
+  --> $DIR/recursive-ice-101862.rs:4:1
+   |
+LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     vec![].append(&mut ice(x.as_ref()));
+   |                        --------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error[E0792]: expected generic type parameter, found `&str`
+  --> $DIR/recursive-ice-101862.rs:6:5
+   |
+LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
+   |               --------------- this generic parameter must be used with a generic type parameter
+LL |
+LL |     vec![].append(&mut ice(x.as_ref()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr
index 216f4cda698..4ca71c5f067 100644
--- a/tests/ui/inference/str-as-char.stderr
+++ b/tests/ui/inference/str-as-char.stderr
@@ -4,7 +4,7 @@ error: character literal may only contain one codepoint
 LL |     let _: &str = '"""';
    |                   ^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "\"\"\"";
    |                   ~~~~~~~~
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let _: &str = '\"\"\"';
    |                   ^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "\"\"\"";
-   |                   ~~~~~~~~
+   |                   ~      ~
 
 error: character literal may only contain one codepoint
   --> $DIR/str-as-char.rs:10:19
@@ -26,7 +26,7 @@ error: character literal may only contain one codepoint
 LL |     let _: &str = '"\"\"\\"\\"';
    |                   ^^^^^^^^^^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "\"\"\\"\\"\\\"";
    |                   ~~~~~~~~~~~~~~~~~~~~
@@ -39,10 +39,10 @@ LL |     let _: &str = 'a';
    |            |
    |            expected due to this
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "a";
-   |                   ~~~
+   |                   ~ ~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr
index 1a91f5e04db..21d383b0e8c 100644
--- a/tests/ui/issues/issue-23589.stderr
+++ b/tests/ui/issues/issue-23589.stderr
@@ -15,10 +15,10 @@ error[E0308]: mismatched types
 LL |     let v: Vec(&str) = vec!['1', '2'];
    |                             ^^^ expected `&str`, found `char`
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let v: Vec(&str) = vec!["1", '2'];
-   |                             ~~~
+   |                             ~ ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr
index 1518a37ab53..76cde00404a 100644
--- a/tests/ui/lexer/lex-bad-char-literals-2.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL |     'nope'
    |     ^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     "nope"
-   |     ~~~~~~
+   |     ~    ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr
index 62a5e424cb4..3f339b2ef7d 100644
--- a/tests/ui/lexer/lex-bad-char-literals-3.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL | static c: char = '●●';
    |                  ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL | static c: char = "●●";
-   |                  ~~~~
+   |                  ~  ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-3.rs:5:20
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let ch: &str = '●●';
    |                    ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let ch: &str = "●●";
-   |                    ~~~~
+   |                    ~  ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr
index 184817a6579..8004157e87f 100644
--- a/tests/ui/lexer/lex-bad-char-literals-5.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL | static c: char = '\x10\x10';
    |                  ^^^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL | static c: char = "\x10\x10";
-   |                  ~~~~~~~~~~
+   |                  ~        ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-5.rs:5:20
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let ch: &str = '\x10\x10';
    |                    ^^^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let ch: &str = "\x10\x10";
-   |                    ~~~~~~~~~~
+   |                    ~        ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr
index 2fe30304a50..96d409d59bb 100644
--- a/tests/ui/lexer/lex-bad-char-literals-6.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL |     let x: &str = 'ab';
    |                   ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let x: &str = "ab";
-   |                   ~~~~
+   |                   ~  ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-6.rs:4:19
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let y: char = 'cd';
    |                   ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let y: char = "cd";
-   |                   ~~~~
+   |                   ~  ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-6.rs:6:13
@@ -26,10 +26,10 @@ error: character literal may only contain one codepoint
 LL |     let z = 'ef';
    |             ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let z = "ef";
-   |             ~~~~
+   |             ~  ~
 
 error[E0308]: mismatched types
   --> $DIR/lex-bad-char-literals-6.rs:13:20
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed
new file mode 100644
index 00000000000..b12139b0b40
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed
@@ -0,0 +1,6 @@
+//@ run-rustfix
+fn main() {
+    println!("1 + 1");
+    //~^ ERROR unterminated character literal
+    //~| ERROR lifetimes cannot start with a number
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs
new file mode 100644
index 00000000000..6548792f33b
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs
@@ -0,0 +1,6 @@
+//@ run-rustfix
+fn main() {
+    println!('1 + 1');
+    //~^ ERROR unterminated character literal
+    //~| ERROR lifetimes cannot start with a number
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr
new file mode 100644
index 00000000000..57c5f82704e
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr
@@ -0,0 +1,20 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-1.rs:3:20
+   |
+LL |     println!('1 + 1');
+   |                    ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("1 + 1");
+   |              ~     ~
+
+error: lifetimes cannot start with a number
+  --> $DIR/lex-bad-str-literal-as-char-1.rs:3:14
+   |
+LL |     println!('1 + 1');
+   |              ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed
new file mode 100644
index 00000000000..3ccec537c6c
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed
@@ -0,0 +1,4 @@
+//@ run-rustfix
+fn main() {
+    println!(" 1 + 1"); //~ ERROR character literal may only contain one codepoint
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs
new file mode 100644
index 00000000000..8af72e47dbb
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs
@@ -0,0 +1,4 @@
+//@ run-rustfix
+fn main() {
+    println!(' 1 + 1'); //~ ERROR character literal may only contain one codepoint
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr
new file mode 100644
index 00000000000..f64761af641
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr
@@ -0,0 +1,13 @@
+error: character literal may only contain one codepoint
+  --> $DIR/lex-bad-str-literal-as-char-2.rs:3:14
+   |
+LL |     println!(' 1 + 1');
+   |              ^^^^^^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!(" 1 + 1");
+   |              ~      ~
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
new file mode 100644
index 00000000000..0ae227da5f1
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
@@ -0,0 +1,7 @@
+//@ revisions: rust2015 rust2018 rust2021
+//@[rust2018] edition:2018
+//@[rust2021] edition:2021
+fn main() {
+    println!('hello world');
+    //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr
new file mode 100644
index 00000000000..06f12742667
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr
@@ -0,0 +1,14 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
+   |
+LL |     println!('hello world');
+   |                          ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr
new file mode 100644
index 00000000000..06f12742667
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr
@@ -0,0 +1,14 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
+   |
+LL |     println!('hello world');
+   |                          ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
new file mode 100644
index 00000000000..06f12742667
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
@@ -0,0 +1,14 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
+   |
+LL |     println!('hello world');
+   |                          ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/nll/ice-106874.rs b/tests/ui/nll/ice-106874.rs
new file mode 100644
index 00000000000..9337eee961b
--- /dev/null
+++ b/tests/ui/nll/ice-106874.rs
@@ -0,0 +1,48 @@
+// issue: rust-lang/rust#106874
+// ICE BoundUniversalRegionError
+
+use std::marker::PhantomData;
+use std::rc::Rc;
+
+pub fn func<V, F: Fn(&mut V)>(f: F) -> A<impl X> {
+    A(B(C::new(D::new(move |st| f(st)))))
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR higher-ranked subtype error
+    //~| ERROR higher-ranked subtype error
+}
+
+trait X {}
+trait Y {
+    type V;
+}
+
+struct A<T>(T);
+
+struct B<T>(Rc<T>);
+impl<T> X for B<T> {}
+
+struct C<T: Y>(T::V);
+impl<T: Y> C<T> {
+    fn new(_: T) -> Rc<Self> {
+        todo!()
+    }
+}
+struct D<V, F>(F, PhantomData<fn(&mut V)>);
+
+impl<V, F> D<V, F> {
+    fn new(_: F) -> Self {
+        todo!()
+    }
+}
+impl<V, F: Fn(&mut V)> Y for D<V, F> {
+    type V = V;
+}
+
+pub fn main() {}
diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr
new file mode 100644
index 00000000000..ead4d490a62
--- /dev/null
+++ b/tests/ui/nll/ice-106874.stderr
@@ -0,0 +1,90 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:5
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:5
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Fn` is not general enough
+  --> $DIR/ice-106874.rs:8:7
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:7
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `Fn` is not general enough
+  --> $DIR/ice-106874.rs:8:7
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:9
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |         ^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `Fn` is not general enough
+  --> $DIR/ice-106874.rs:8:9
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:9
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: higher-ranked subtype error
+  --> $DIR/ice-106874.rs:8:41
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |                                         ^
+
+error: higher-ranked subtype error
+  --> $DIR/ice-106874.rs:8:41
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |                                         ^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/panics/panic-in-message-fmt.rs b/tests/ui/panics/panic-in-message-fmt.rs
new file mode 100644
index 00000000000..e5bedf96b35
--- /dev/null
+++ b/tests/ui/panics/panic-in-message-fmt.rs
@@ -0,0 +1,25 @@
+// Checks what happens when formatting the panic message panics.
+
+//@ run-fail
+//@ exec-env:RUST_BACKTRACE=0
+//@ check-run-results
+//@ error-pattern: panicked while processing panic
+//@ normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
+//@ normalize-stderr-test: "\n +at [^\n]+" -> ""
+//@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
+//@ ignore-emscripten "RuntimeError" junk in output
+
+use std::fmt::{Display, self};
+
+struct MyStruct;
+
+impl Display for MyStruct {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        todo!()
+    }
+}
+
+fn main() {
+    let instance = MyStruct;
+    panic!("this is wrong: {}", instance);
+}
diff --git a/tests/ui/panics/panic-in-message-fmt.run.stderr b/tests/ui/panics/panic-in-message-fmt.run.stderr
new file mode 100644
index 00000000000..c3a5733c8ae
--- /dev/null
+++ b/tests/ui/panics/panic-in-message-fmt.run.stderr
@@ -0,0 +1,2 @@
+panicked at $DIR/panic-in-message-fmt.rs:18:9:
+thread panicked while processing panic. aborting.
diff --git a/tests/ui/parser/issues/issue-64732.rs b/tests/ui/parser/issues/issue-64732.rs
index 2db51ea6042..ff0f97ea211 100644
--- a/tests/ui/parser/issues/issue-64732.rs
+++ b/tests/ui/parser/issues/issue-64732.rs
@@ -5,5 +5,5 @@ fn main() {
     //~| HELP if you meant to write a byte string literal, use double quotes
     let _bar = 'hello';
     //~^ ERROR character literal may only contain one codepoint
-    //~| HELP if you meant to write a `str` literal, use double quotes
+    //~| HELP if you meant to write a string literal, use double quotes
 }
diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr
index 80462549377..7ec2df6d3bf 100644
--- a/tests/ui/parser/issues/issue-64732.stderr
+++ b/tests/ui/parser/issues/issue-64732.stderr
@@ -7,7 +7,7 @@ LL |     let _foo = b'hello\0';
 help: if you meant to write a byte string literal, use double quotes
    |
 LL |     let _foo = b"hello\0";
-   |                ~~~~~~~~~~
+   |                ~~       ~
 
 error: character literal may only contain one codepoint
   --> $DIR/issue-64732.rs:6:16
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let _bar = 'hello';
    |                ^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _bar = "hello";
-   |                ~~~~~~~
+   |                ~     ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/unicode-character-literal.fixed b/tests/ui/parser/unicode-character-literal.fixed
index 9e31890151c..e401ecaf5da 100644
--- a/tests/ui/parser/unicode-character-literal.fixed
+++ b/tests/ui/parser/unicode-character-literal.fixed
@@ -7,12 +7,12 @@ fn main() {
     let _spade = "♠️";
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _s = "ṩ̂̊";
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _a = 'Å';
     //~^ ERROR: character literal may only contain one codepoint
diff --git a/tests/ui/parser/unicode-character-literal.rs b/tests/ui/parser/unicode-character-literal.rs
index d886e5b26a5..428e4e1ac5a 100644
--- a/tests/ui/parser/unicode-character-literal.rs
+++ b/tests/ui/parser/unicode-character-literal.rs
@@ -7,12 +7,12 @@ fn main() {
     let _spade = '♠️';
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _s = 'ṩ̂̊';
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _a = 'Å';
     //~^ ERROR: character literal may only contain one codepoint
diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr
index 5cd3bd0fe69..726cde2b413 100644
--- a/tests/ui/parser/unicode-character-literal.stderr
+++ b/tests/ui/parser/unicode-character-literal.stderr
@@ -9,10 +9,10 @@ note: this `♠` is followed by the combining mark `\u{fe0f}`
    |
 LL |     let _spade = '♠️';
    |                   ^
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _spade = "♠️";
-   |                  ~~~
+   |                  ~ ~
 
 error: character literal may only contain one codepoint
   --> $DIR/unicode-character-literal.rs:12:14
@@ -25,10 +25,10 @@ note: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}`
    |
 LL |     let _s = 'ṩ̂̊';
    |               ^
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _s = "ṩ̂̊";
-   |              ~~~
+   |              ~ ~
 
 error: character literal may only contain one codepoint
   --> $DIR/unicode-character-literal.rs:17:14
diff --git a/tests/ui/polymorphization/ice-poly-with-mir-opts-90192.rs b/tests/ui/polymorphization/ice-poly-with-mir-opts-90192.rs
new file mode 100644
index 00000000000..4557c7e517c
--- /dev/null
+++ b/tests/ui/polymorphization/ice-poly-with-mir-opts-90192.rs
@@ -0,0 +1,20 @@
+// issue: rust-lang/rust#90192
+// ICE assertion failed: matches!(ty.kind(), ty :: Param(_))
+//@ compile-flags:-Zpolymorphize=on -Zmir-opt-level=3
+//@ build-pass
+
+fn test<T>() {
+    std::mem::size_of::<T>();
+}
+
+pub fn foo<T>(_: T) -> &'static fn() {
+    &(test::<T> as fn())
+}
+
+fn outer<T>() {
+    foo(|| ());
+}
+
+fn main() {
+    outer::<u8>();
+}
diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout
index e1be98f85d8..1df4d85d09e 100644
--- a/tests/ui/print_type_sizes/async.stdout
+++ b/tests/ui/print_type_sizes/async.stdout
@@ -5,7 +5,7 @@ print-type-size         upvar `.arg`: 8192 bytes
 print-type-size     variant `Suspend0`: 16385 bytes
 print-type-size         upvar `.arg`: 8192 bytes
 print-type-size         local `.arg`: 8192 bytes
-print-type-size         local `.__awaitee`: 1 bytes
+print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async.rs:8:17: 8:19}
 print-type-size     variant `Returned`: 8192 bytes
 print-type-size         upvar `.arg`: 8192 bytes
 print-type-size     variant `Panicked`: 8192 bytes
diff --git a/tests/ui/privacy/decl-macro-infinite-global-import-cycle-ice-64784.rs b/tests/ui/privacy/decl-macro-infinite-global-import-cycle-ice-64784.rs
new file mode 100644
index 00000000000..72b1ea7ccc8
--- /dev/null
+++ b/tests/ui/privacy/decl-macro-infinite-global-import-cycle-ice-64784.rs
@@ -0,0 +1,16 @@
+// ICE #64784  already borrowed: BorrowMutError
+//@ check-pass
+// issue: rust-lang/rust#64784
+#![feature(decl_macro)]
+
+pub macro m($i:ident, $j:ident) {
+    mod $i {
+        pub use crate::$j::*;
+        pub struct A;
+    }
+}
+
+m!(x, y);
+m!(y, x);
+
+fn main() {}
diff --git a/tests/ui/privacy/pub-priv-dep/auxiliary/bar.rs b/tests/ui/privacy/pub-priv-dep/auxiliary/bar.rs
new file mode 100644
index 00000000000..58297c92693
--- /dev/null
+++ b/tests/ui/privacy/pub-priv-dep/auxiliary/bar.rs
@@ -0,0 +1,6 @@
+//@ aux-crate:priv:foo=foo.rs
+//@ compile-flags: -Zunstable-options
+
+#![crate_type = "rlib"]
+extern crate foo;
+pub struct Bar(pub i32);
diff --git a/tests/ui/privacy/pub-priv-dep/auxiliary/foo.rs b/tests/ui/privacy/pub-priv-dep/auxiliary/foo.rs
new file mode 100644
index 00000000000..6fd950619e6
--- /dev/null
+++ b/tests/ui/privacy/pub-priv-dep/auxiliary/foo.rs
@@ -0,0 +1,2 @@
+#![crate_type = "rlib"]
+pub struct Foo(pub i32);
diff --git a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
new file mode 100644
index 00000000000..d7ade7f0e96
--- /dev/null
+++ b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
@@ -0,0 +1,12 @@
+//@ aux-build: bar.rs
+//@ aux-build: foo.rs
+//@ build-pass
+
+#![deny(exported_private_dependencies)]
+
+// Ensure the libbar.rlib is loaded first. If the command line parameter `--extern foo` does not
+// exist, previus version would fail to compile
+#![crate_type = "rlib"]
+extern crate bar;
+extern crate foo;
+pub fn baz() -> (Option<foo::Foo>, Option<bar::Bar>) { (None, None) }
diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs
new file mode 100644
index 00000000000..87ce4f1e14d
--- /dev/null
+++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs
@@ -0,0 +1,15 @@
+// issue: rust-lang/rust#105047
+// ICE raw ptr comparison should already be caught in the trait systems
+
+#![feature(raw_ref_op)]
+
+const RCZ: *const i32 = &raw const *&0;
+
+const fn f() {
+    if let RCZ = &raw const *&0 { }
+    //~^ WARN function pointers and raw pointers not derived from integers in patterns
+    //~| ERROR pointers cannot be reliably compared during const eval
+    //~| WARN this was previously accepted by the compiler but is being phased out
+}
+
+fn main() {}
diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr
new file mode 100644
index 00000000000..9c472cda244
--- /dev/null
+++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr
@@ -0,0 +1,31 @@
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/const-eval-compare-ice-105047.rs:9:12
+   |
+LL |     if let RCZ = &raw const *&0 { }
+   |            ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+error: pointers cannot be reliably compared during const eval
+  --> $DIR/const-eval-compare-ice-105047.rs:9:12
+   |
+LL |     if let RCZ = &raw const *&0 { }
+   |            ^^^
+   |
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/const-eval-compare-ice-105047.rs:9:12
+   |
+LL |     if let RCZ = &raw const *&0 { }
+   |            ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/sanitizer/cfi-self-ref.rs b/tests/ui/sanitizer/cfi-self-ref.rs
new file mode 100644
index 00000000000..32d0b100702
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-self-ref.rs
@@ -0,0 +1,33 @@
+// Check that encoding self-referential types works with #[repr(transparent)]
+
+//@ needs-sanitizer-cfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
+//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
+//@ run-pass
+
+use std::marker::PhantomData;
+
+struct X<T> {
+    _x: u8,
+    p: PhantomData<T>,
+}
+
+#[repr(transparent)]
+struct Y(X<Y>);
+
+trait Fooable {
+    fn foo(&self, y: Y);
+}
+
+struct Bar;
+
+impl Fooable for Bar {
+    fn foo(&self, _: Y) {}
+}
+
+fn main() {
+    let x = &Bar as &dyn Fooable;
+    x.foo(Y(X {_x: 0, p: PhantomData}));
+}
diff --git a/tests/ui/sanitizer/cfi-virtual-auto.rs b/tests/ui/sanitizer/cfi-virtual-auto.rs
new file mode 100644
index 00000000000..7a0c246a412
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-virtual-auto.rs
@@ -0,0 +1,22 @@
+// Tests that calling a trait object method on a trait object with additional auto traits works.
+
+//@ needs-sanitizer-cfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
+//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
+//@ run-pass
+
+trait Foo {
+    fn foo(&self);
+}
+
+struct Bar;
+impl Foo for Bar {
+    fn foo(&self) {}
+}
+
+pub fn main() {
+    let x: &(dyn Foo + Send) = &Bar;
+    x.foo();
+}
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
new file mode 100644
index 00000000000..3f8011d961a
--- /dev/null
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
@@ -0,0 +1,25 @@
+error[E0391]: cycle detected when computing layout of `Foo`
+   |
+   = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
+   = note: ...which again requires computing layout of `Foo`, completing the cycle
+note: cycle used when const-evaluating + checking `_`
+  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+   |
+LL | const _: *const Foo = 0 as _;
+   | ^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+   |
+LL | const _: *const Foo = 0 as _;
+   | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0080, E0391.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
new file mode 100644
index 00000000000..04e2c4483bf
--- /dev/null
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
@@ -0,0 +1,25 @@
+error[E0391]: cycle detected when computing layout of `Foo`
+   |
+   = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
+   = note: ...which again requires computing layout of `Foo`, completing the cycle
+note: cycle used when const-evaluating + checking `_`
+  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+   |
+LL | const _: *const Foo = 0 as _;
+   | ^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+   |
+LL | const _: *const Foo = 0 as _;
+   | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
+   |
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0080, E0391.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs
new file mode 100644
index 00000000000..54d50346cc8
--- /dev/null
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs
@@ -0,0 +1,18 @@
+// #98842 stack overflow in trait inference
+// issue: rust-lang/rust#98842
+//@ check-fail
+//@ edition:2021
+//@ stderr-per-bitwidth
+//@ ignore-endian-big
+//~^^^^^^ ERROR cycle detected when computing layout of `Foo`
+
+// If the inner `Foo` is named through an associated type,
+// the "infinite size" error does not occur.
+struct Foo(<&'static Foo as ::core::ops::Deref>::Target);
+// But Rust will be unable to know whether `Foo` is sized or not,
+// and it will infinitely recurse somewhere trying to figure out the
+// size of this pointer (is my guess):
+const _: *const Foo = 0 as _;
+//~^ ERROR it is undefined behavior to use this value
+
+pub fn main() {}
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr
new file mode 100644
index 00000000000..8ddddeb5bf2
--- /dev/null
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr
@@ -0,0 +1,25 @@
+error[E0391]: cycle detected when computing layout of `Foo`
+   |
+   = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
+   = note: ...which again requires computing layout of `Foo`, completing the cycle
+note: cycle used when const-evaluating + checking `_`
+  --> $DIR/stack-overflow-trait-infer-98842.rs:13:1
+   |
+LL | const _: *const Foo = 0 as _;
+   | ^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/stack-overflow-trait-infer-98842.rs:13:1
+   |
+LL | const _: *const Foo = 0 as _;
+   | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
+   |
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0080, E0391.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/specialization/broken-mir-drop-glue-107228.rs b/tests/ui/specialization/broken-mir-drop-glue-107228.rs
new file mode 100644
index 00000000000..5a6dbf9ffc7
--- /dev/null
+++ b/tests/ui/specialization/broken-mir-drop-glue-107228.rs
@@ -0,0 +1,28 @@
+// issue: rust-lang/rust#107228
+// ICE broken MIR in DropGlue
+//@ compile-flags: -Zvalidate-mir
+//@ check-pass
+
+#![feature(specialization)]
+#![crate_type="lib"]
+#![allow(incomplete_features)]
+
+pub(crate) trait SpecTrait {
+    type Assoc;
+}
+
+impl<C> SpecTrait for C {
+    default type Assoc = Vec<Self>;
+}
+
+pub(crate) struct AssocWrap<C: SpecTrait> {
+    _assoc: C::Assoc,
+}
+
+fn instantiate<C: SpecTrait>() -> AssocWrap<C> {
+    loop {}
+}
+
+pub fn main() {
+    instantiate::<()>();
+}
diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr
index 44ec079e929..0638d371c17 100644
--- a/tests/ui/str/str-as-char.stderr
+++ b/tests/ui/str/str-as-char.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL |     println!('●●');
    |              ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     println!("●●");
-   |              ~~~~
+   |              ~  ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
new file mode 100644
index 00000000000..57f814bc81e
--- /dev/null
+++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Znext-solver
+
+trait Tr<'a> {}
+
+// Fulfillment in the new solver relies on an invariant to hold: Either
+// `has_changed` is true, or computing a goal's certainty is idempotent.
+// This isn't true for `ReError`, which we used to pass through in the
+// canonicalizer even on input mode, which can cause a goal to go from
+// ambig => pass, but we don't consider `has_changed` when the response
+// only contains region constraints (since we usually uniquify regions).
+//
+//   In this test:
+// Implicit negative coherence tries to prove `W<?0>: Constrain<'?1>`,
+// which will then match with the impl below. This constrains `'?1` to
+// `ReError`, but still bails w/ ambiguity bc we can't prove `?0: Sized`.
+// Then, when we recompute the goal `W<?0>: Constrain<'error>`, when
+// collecting ambiguities and overflows, we end up assembling a default
+// error candidate w/o ambiguity, which causes the goal to pass, and ICE.
+impl<'a, A: ?Sized> Tr<'a> for W<A> {}
+struct W<A: ?Sized>(A);
+impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
+//~^ ERROR conflicting implementations of trait `Tr<'_>` for type `W<_>`
+
+trait Constrain<'a> {}
+impl<A: Sized> Constrain<'missing> for W<A> {}
+//~^ ERROR use of undeclared lifetime name `'missing`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
new file mode 100644
index 00000000000..cf85c52fb42
--- /dev/null
+++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
@@ -0,0 +1,21 @@
+error[E0261]: use of undeclared lifetime name `'missing`
+  --> $DIR/dont-canonicalize-re-error.rs:25:26
+   |
+LL | impl<A: Sized> Constrain<'missing> for W<A> {}
+   |      -                   ^^^^^^^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'missing` here: `'missing,`
+
+error[E0119]: conflicting implementations of trait `Tr<'_>` for type `W<_>`
+  --> $DIR/dont-canonicalize-re-error.rs:21:1
+   |
+LL | impl<'a, A: ?Sized> Tr<'a> for W<A> {}
+   | ----------------------------------- first implementation here
+LL | struct W<A: ?Sized>(A);
+LL | impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0261.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
new file mode 100644
index 00000000000..3af299e5b11
--- /dev/null
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
@@ -0,0 +1,15 @@
+trait FromResidual<R = <Self as Try>::Residual> {
+    fn from_residual(residual: R) -> Self;
+}
+
+trait Try {
+    type Residual;
+}
+
+fn w<'a, T: 'a, F: Fn(&'a T)>() {
+    let b: &dyn FromResidual = &();
+    //~^ ERROR: the trait `FromResidual` cannot be made into an object
+    //~| ERROR: the trait `FromResidual` cannot be made into an object
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
new file mode 100644
index 00000000000..d5e9b1be63b
--- /dev/null
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `FromResidual` cannot be made into an object
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17
+   |
+LL |     let b: &dyn FromResidual = &();
+   |                 ^^^^^^^^^^^^
+   |
+   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+
+error[E0038]: the trait `FromResidual` cannot be made into an object
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12
+   |
+LL |     let b: &dyn FromResidual = &();
+   |            ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
+   |
+LL | trait FromResidual<R = <Self as Try>::Residual> {
+   |       ------------ this trait cannot be made into an object...
+LL |     fn from_residual(residual: R) -> Self;
+   |        ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter
+help: consider turning `from_residual` into a method by giving it a `&self` argument
+   |
+LL |     fn from_residual(&self, residual: R) -> Self;
+   |                      ++++++
+help: alternatively, consider constraining `from_residual` so it does not apply to trait objects
+   |
+LL |     fn from_residual(residual: R) -> Self where Self: Sized;
+   |                                           +++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs
new file mode 100644
index 00000000000..023991c29d0
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs
@@ -0,0 +1,36 @@
+// issue: rust-lang/rust#99945
+// ICE Failed to normalize
+
+#![feature(type_alias_impl_trait)]
+
+trait Widget<E> {
+    type State;
+
+    fn make_state(&self) -> Self::State;
+}
+
+impl<E> Widget<E> for () {
+    type State = ();
+
+    fn make_state(&self) -> Self::State {}
+}
+
+struct StatefulWidget<F>(F);
+
+type StateWidget<'a> = impl Widget<&'a ()>;
+
+impl<F: for<'a> Fn(&'a ()) -> StateWidget<'a>> Widget<()> for StatefulWidget<F> {
+    type State = ();
+
+    fn make_state(&self) -> Self::State {}
+}
+
+fn new_stateful_widget<F: for<'a> Fn(&'a ()) -> StateWidget<'a>>(build: F) -> impl Widget<()> {
+    StatefulWidget(build)
+    //~^ ERROR expected generic lifetime parameter, found `'a`
+}
+
+fn main() {
+    new_stateful_widget(|_| ()).make_state();
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr
new file mode 100644
index 00000000000..0c76feae198
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/failed-to-normalize-ice-99945.rs:34:29
+   |
+LL | type StateWidget<'a> = impl Widget<&'a ()>;
+   |                        ------------------- the expected opaque type
+...
+LL |     new_stateful_widget(|_| ()).make_state();
+   |                             ^^ expected opaque type, found `()`
+   |
+   = note: expected opaque type `StateWidget<'_>`
+                found unit type `()`
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/failed-to-normalize-ice-99945.rs:29:5
+   |
+LL | type StateWidget<'a> = impl Widget<&'a ()>;
+   |                  -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     StatefulWidget(build)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0792.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/type-alias-impl-trait/tait-param-inference-issue-117310.rs b/tests/ui/type-alias-impl-trait/tait-param-inference-issue-117310.rs
new file mode 100644
index 00000000000..be743e8e270
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/tait-param-inference-issue-117310.rs
@@ -0,0 +1,28 @@
+//@ check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+use std::ops::Deref;
+
+trait Trait {}
+impl<A, B> Trait for (A, B, u8) where A: Deref, B: Deref<Target = A::Target>, {}
+impl<A, B> Trait for (A, B, i8) {}
+
+type TaitSized = impl Sized;
+fn def_tait1() -> TaitSized {}
+
+type TaitCopy = impl Copy;
+fn def_tait2() -> TaitCopy {}
+
+fn impl_trait<T: Trait> () {}
+
+fn test() {
+    impl_trait::<(&TaitSized, &TaitCopy, _)>();
+    impl_trait::<(&TaitCopy, &TaitSized, _)>();
+
+    impl_trait::<(&TaitCopy, &String, _)>();
+    impl_trait::<(&TaitSized, &String, _)>();
+}
+
+fn main() {}
diff --git a/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs
new file mode 100644
index 00000000000..ec475673d0d
--- /dev/null
+++ b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs
@@ -0,0 +1,21 @@
+// ICE size_and_align_of::<[closure@test.rs:15:5: 17:7]> not supported #88212
+// issue: rust-lang/rust#88212
+#![feature(unsized_locals)]
+//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+
+trait Example {}
+struct Foo();
+
+impl Example for Foo {}
+
+fn example() -> Box<dyn Example> {
+    Box::new(Foo())
+}
+
+fn main() {
+    let x: dyn Example = *example();
+    (move || {
+        let _y = x;
+        //~^ ERROR the size for values of type `dyn Example` cannot be known at compilation time
+    })();
+}
diff --git a/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr
new file mode 100644
index 00000000000..a0253ac1f35
--- /dev/null
+++ b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr
@@ -0,0 +1,23 @@
+warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/ice-size_and_align_of-closure-not-supported-88212.rs:3:12
+   |
+LL | #![feature(unsized_locals)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the size for values of type `dyn Example` cannot be known at compilation time
+  --> $DIR/ice-size_and_align_of-closure-not-supported-88212.rs:18:18
+   |
+LL |     (move || {
+   |           -- this closure captures all values by move
+LL |         let _y = x;
+   |                  ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn Example`
+   = note: all values captured by value by a closure must have a statically known size
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
index 107cfbb9ff6..db155f4fa3c 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
@@ -1,11 +1,30 @@
 trait Trait<const N: Trait = bar> {
-//~^ ERROR cannot find value `bar` in this scope
-//~| ERROR cycle detected when computing type of `Trait::N`
-//~| ERROR cycle detected when computing type of `Trait::N`
-//~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-//~| WARN trait objects without an explicit `dyn` are deprecated
-//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-    fn fnc(&self) {
+    //~^ ERROR cannot find value `bar` in this scope
+    //~| ERROR cycle detected when computing type of `Trait::N`
+    //~| ERROR cycle detected when computing type of `Trait::N`
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    fn fnc<const N: Trait = u32>(&self) -> Trait {
+    //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters
+    //~| ERROR expected value, found builtin type `u32`
+    //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+    //~| ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+        bar
+    //~^ ERROR cannot find value `bar` in this scope
     }
 }
 
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
index 2d5a0ede962..cf985d9d1fd 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
@@ -1,9 +1,30 @@
+error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:18
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                   - first use of `N`
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                  ^ already used
+
 error[E0425]: cannot find value `bar` in this scope
   --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:30
    |
 LL | trait Trait<const N: Trait = bar> {
    |                              ^^^ not found in this scope
 
+error[E0423]: expected value, found builtin type `u32`
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:29
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                             ^^^ not a value
+
+error[E0425]: cannot find value `bar` in this scope
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:26:9
+   |
+LL |         bar
+   |         ^^^ not found in this scope
+
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
    |
@@ -46,6 +67,84 @@ LL | trait Trait<const N: Trait = bar> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
+error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:12
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |            ^^^^^^^^^^^^^^^^^^^^
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
+   |                     +++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:44
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                                            ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
+   |                                            +++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL | trait Trait<const N: dyn Trait = bar> {
+   |                      +++
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+
 error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
   --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
    |
@@ -54,7 +153,76 @@ LL | trait Trait<const N: Trait = bar> {
    |
    = note: the only supported types are integers, `bool` and `char`
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:44
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- in this trait
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                                            ^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Self {
+   |                                            ~~~~
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
+   |                     +++
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+
+error: aborting due to 14 previous errors; 5 warnings emitted
 
-Some errors have detailed explanations: E0391, E0425.
-For more information about an error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425.
+For more information about an error, try `rustc --explain E0038`.