about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/post-merge.yml42
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock32
-rw-r--r--compiler/rustc_abi/Cargo.toml8
-rw-r--r--compiler/rustc_abi/src/layout.rs192
-rw-r--r--compiler/rustc_abi/src/layout/coroutine.rs320
-rw-r--r--compiler/rustc_abi/src/layout/simple.rs148
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs6
-rw-r--r--compiler/rustc_abi/src/lib.rs49
-rw-r--r--compiler/rustc_arena/src/lib.rs26
-rw-r--r--compiler/rustc_ast/src/ast.rs14
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs7
-rw-r--r--compiler/rustc_ast/src/util/classify.rs2
-rw-r--r--compiler/rustc_ast/src/visit.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs30
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs44
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs4
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs9
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs44
-rw-r--r--compiler/rustc_attr_parsing/Cargo.toml1
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs44
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/constraints/graph.rs128
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs20
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs97
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs37
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs29
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch6
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/type_.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs156
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs98
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs141
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs143
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs54
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl28
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs31
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs112
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs104
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs34
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/abi.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_data_structures/src/aligned.rs8
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs6
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs2
-rw-r--r--compiler/rustc_errors/src/emitter.rs244
-rw-r--r--compiler/rustc_errors/src/lib.rs1
-rw-r--r--compiler/rustc_errors/src/markdown/parse.rs20
-rw-r--r--compiler/rustc_errors/src/styled_buffer.rs13
-rw-r--r--compiler/rustc_feature/src/unstable.rs19
-rw-r--r--compiler/rustc_hir/src/def.rs22
-rw-r--r--compiler/rustc_hir/src/definitions.rs22
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_hir/src/intravisit.rs45
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/always_applicable.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs110
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs132
-rw-r--r--compiler/rustc_hir_pretty/Cargo.toml2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs81
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs68
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs64
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs89
-rw-r--r--compiler/rustc_incremental/Cargo.toml2
-rw-r--r--compiler/rustc_incremental/src/persist/file_format.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs4
-rw-r--r--compiler/rustc_index/src/bit_set.rs6
-rw-r--r--compiler/rustc_index/src/vec/tests.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/dangling.rs5
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs2
-rw-r--r--compiler/rustc_lint/src/late.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs39
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp10
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp8
-rw-r--r--compiler/rustc_middle/Cargo.toml3
-rw-r--r--compiler/rustc_middle/src/hir/map.rs2
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs2
-rw-r--r--compiler/rustc_middle/src/query/erase.rs16
-rw-r--r--compiler/rustc_middle/src/query/mod.rs13
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs6
-rw-r--r--compiler/rustc_middle/src/thir.rs8
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs3
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs7
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs9
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs7
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs47
-rw-r--r--compiler/rustc_middle/src/ty/list.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs60
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs8
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/significant_drop_order.rs6
-rw-r--r--compiler/rustc_middle/src/ty/util.rs12
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_place.rs1
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs8
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/category.rs1
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/into.rs56
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs17
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs7
-rw-r--r--compiler/rustc_mir_transform/src/add_call_guards.rs61
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs5
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs4
-rw-r--r--compiler/rustc_parse/messages.ftl8
-rw-r--r--compiler/rustc_parse/src/errors.rs28
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs44
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs30
-rw-r--r--compiler/rustc_parse/src/parser/item.rs19
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs6
-rw-r--r--compiler/rustc_parse/src/parser/token_type.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/input_stats.rs11
-rw-r--r--compiler/rustc_passes/src/liveness.rs11
-rw-r--r--compiler/rustc_passes/src/liveness/rwu_table.rs2
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs1
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs3
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs11
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs52
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs48
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_serialize/src/leb128.rs2
-rw-r--r--compiler/rustc_session/src/config.rs56
-rw-r--r--compiler/rustc_session/src/filesearch.rs2
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--compiler/rustc_span/src/edition.rs29
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs7
-rw-r--r--compiler/rustc_target/src/callconv/x86.rs24
-rw-r--r--compiler/rustc_target/src/callconv/x86_win32.rs81
-rw-r--r--compiler/rustc_target/src/spec/mod.rs11
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs2
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs7
-rw-r--r--compiler/rustc_ty_utils/messages.ftl2
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs6
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs16
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs5
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs587
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs58
-rw-r--r--compiler/stable_mir/src/mir/alloc.rs4
-rw-r--r--library/Cargo.lock14
-rw-r--r--library/Cargo.toml1
-rw-r--r--library/alloc/Cargo.toml26
-rw-r--r--library/alloc/src/alloc.rs18
-rw-r--r--library/alloc/src/borrow.rs6
-rw-r--r--library/alloc/src/boxed/convert.rs28
-rw-r--r--library/alloc/src/boxed/thin.rs22
-rw-r--r--library/alloc/src/bstr.rs20
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs5
-rw-r--r--library/alloc/src/collections/btree/node/tests.rs8
-rw-r--r--library/alloc/src/collections/mod.rs24
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs1
-rw-r--r--library/alloc/src/collections/vec_deque/spec_extend.rs2
-rw-r--r--library/alloc/src/collections/vec_deque/spec_from_iter.rs1
-rw-r--r--library/alloc/src/ffi/c_str.rs16
-rw-r--r--library/alloc/src/lib.rs41
-rw-r--r--library/alloc/src/macros.rs23
-rw-r--r--library/alloc/src/raw_vec/mod.rs (renamed from library/alloc/src/raw_vec.rs)8
-rw-r--r--library/alloc/src/raw_vec/tests.rs3
-rw-r--r--library/alloc/src/rc.rs17
-rw-r--r--library/alloc/src/slice.rs186
-rw-r--r--library/alloc/src/str.rs3
-rw-r--r--library/alloc/src/string.rs53
-rw-r--r--library/alloc/src/sync.rs15
-rw-r--r--library/alloc/src/vec/in_place_collect.rs24
-rw-r--r--library/alloc/src/vec/into_iter.rs5
-rw-r--r--library/alloc/src/vec/mod.rs71
-rw-r--r--library/alloc/tests/rc.rs260
-rw-r--r--library/alloctests/Cargo.toml47
-rw-r--r--library/alloctests/benches/binary_heap.rs (renamed from library/alloc/benches/binary_heap.rs)0
-rw-r--r--library/alloctests/benches/btree/map.rs (renamed from library/alloc/benches/btree/map.rs)0
-rw-r--r--library/alloctests/benches/btree/mod.rs (renamed from library/alloc/benches/btree/mod.rs)0
-rw-r--r--library/alloctests/benches/btree/set.rs (renamed from library/alloc/benches/btree/set.rs)0
-rw-r--r--library/alloctests/benches/lib.rs (renamed from library/alloc/benches/lib.rs)0
-rw-r--r--library/alloctests/benches/linked_list.rs (renamed from library/alloc/benches/linked_list.rs)0
-rw-r--r--library/alloctests/benches/slice.rs (renamed from library/alloc/benches/slice.rs)14
-rw-r--r--library/alloctests/benches/str.rs (renamed from library/alloc/benches/str.rs)0
-rw-r--r--library/alloctests/benches/string.rs (renamed from library/alloc/benches/string.rs)0
-rw-r--r--library/alloctests/benches/vec.rs (renamed from library/alloc/benches/vec.rs)8
-rw-r--r--library/alloctests/benches/vec_deque.rs (renamed from library/alloc/benches/vec_deque.rs)0
-rw-r--r--library/alloctests/benches/vec_deque_append.rs (renamed from library/alloc/benches/vec_deque_append.rs)0
-rw-r--r--library/alloctests/lib.rs93
-rw-r--r--library/alloctests/testing/crash_test.rs (renamed from library/alloc/src/testing/crash_test.rs)0
-rw-r--r--library/alloctests/testing/mod.rs (renamed from library/alloc/src/testing/mod.rs)0
-rw-r--r--library/alloctests/testing/ord_chaos.rs (renamed from library/alloc/src/testing/ord_chaos.rs)0
-rw-r--r--library/alloctests/testing/rng.rs (renamed from library/alloc/src/testing/rng.rs)0
-rw-r--r--library/alloctests/tests/alloc_test.rs (renamed from library/alloc/tests/alloc.rs)0
-rw-r--r--library/alloctests/tests/arc.rs (renamed from library/alloc/tests/arc.rs)5
-rw-r--r--library/alloctests/tests/autotraits.rs (renamed from library/alloc/tests/autotraits.rs)0
-rw-r--r--library/alloctests/tests/borrow.rs (renamed from library/alloc/tests/borrow.rs)0
-rw-r--r--library/alloctests/tests/boxed.rs (renamed from library/alloc/tests/boxed.rs)0
-rw-r--r--library/alloctests/tests/btree_set_hash.rs (renamed from library/alloc/tests/btree_set_hash.rs)0
-rw-r--r--library/alloctests/tests/c_str.rs (renamed from library/alloc/tests/c_str.rs)0
-rw-r--r--library/alloctests/tests/c_str2.rs (renamed from library/alloc/tests/c_str2.rs)0
-rw-r--r--library/alloctests/tests/collections/binary_heap.rs (renamed from library/alloc/tests/collections/binary_heap.rs)0
-rw-r--r--library/alloctests/tests/collections/mod.rs (renamed from library/alloc/tests/collections/mod.rs)0
-rw-r--r--library/alloctests/tests/const_fns.rs (renamed from library/alloc/tests/const_fns.rs)0
-rw-r--r--library/alloctests/tests/cow_str.rs (renamed from library/alloc/tests/cow_str.rs)0
-rw-r--r--library/alloctests/tests/fmt.rs (renamed from library/alloc/tests/fmt.rs)0
-rw-r--r--library/alloctests/tests/heap.rs (renamed from library/alloc/tests/heap.rs)0
-rw-r--r--library/alloctests/tests/lib.rs (renamed from library/alloc/tests/lib.rs)3
-rw-r--r--library/alloctests/tests/linked_list.rs (renamed from library/alloc/tests/linked_list.rs)0
-rw-r--r--library/alloctests/tests/misc_tests.rs (renamed from library/alloc/tests/misc_tests.rs)0
-rw-r--r--library/alloctests/tests/rc.rs (renamed from library/alloc/src/rc/tests.rs)276
-rw-r--r--library/alloctests/tests/slice.rs (renamed from library/alloc/tests/slice.rs)4
-rw-r--r--library/alloctests/tests/sort/ffi_types.rs (renamed from library/alloc/tests/sort/ffi_types.rs)0
-rw-r--r--library/alloctests/tests/sort/known_good_stable_sort.rs (renamed from library/alloc/tests/sort/known_good_stable_sort.rs)6
-rw-r--r--library/alloctests/tests/sort/mod.rs (renamed from library/alloc/tests/sort/mod.rs)0
-rw-r--r--library/alloctests/tests/sort/patterns.rs (renamed from library/alloc/tests/sort/patterns.rs)0
-rw-r--r--library/alloctests/tests/sort/tests.rs (renamed from library/alloc/tests/sort/tests.rs)0
-rw-r--r--library/alloctests/tests/sort/zipf.rs (renamed from library/alloc/tests/sort/zipf.rs)0
-rw-r--r--library/alloctests/tests/str.rs (renamed from library/alloc/tests/str.rs)0
-rw-r--r--library/alloctests/tests/string.rs (renamed from library/alloc/tests/string.rs)0
-rw-r--r--library/alloctests/tests/sync.rs (renamed from library/alloc/tests/sync.rs)0
-rw-r--r--library/alloctests/tests/task.rs (renamed from library/alloc/tests/task.rs)0
-rw-r--r--library/alloctests/tests/testing/crash_test.rs (renamed from library/alloc/tests/testing/crash_test.rs)0
-rw-r--r--library/alloctests/tests/testing/mod.rs (renamed from library/alloc/tests/testing/mod.rs)0
-rw-r--r--library/alloctests/tests/thin_box.rs (renamed from library/alloc/tests/thin_box.rs)3
-rw-r--r--library/alloctests/tests/vec.rs (renamed from library/alloc/tests/vec.rs)6
-rw-r--r--library/alloctests/tests/vec_deque.rs (renamed from library/alloc/tests/vec_deque.rs)0
-rw-r--r--library/alloctests/tests/vec_deque_alloc_error.rs (renamed from library/alloc/tests/vec_deque_alloc_error.rs)0
-rw-r--r--library/core/src/alloc/layout.rs4
-rw-r--r--library/core/src/char/convert.rs16
-rw-r--r--library/core/src/char/methods.rs4
-rw-r--r--library/core/src/clone.rs57
-rw-r--r--library/core/src/cmp.rs22
-rw-r--r--library/core/src/ffi/primitives.rs8
-rw-r--r--library/core/src/hash/mod.rs4
-rw-r--r--library/core/src/hash/sip.rs6
-rw-r--r--library/core/src/intrinsics/mod.rs10
-rw-r--r--library/core/src/iter/adapters/map_windows.rs4
-rw-r--r--library/core/src/marker.rs5
-rw-r--r--library/core/src/mem/maybe_uninit.rs4
-rw-r--r--library/core/src/mem/mod.rs48
-rw-r--r--library/core/src/mem/transmutability.rs6
-rw-r--r--library/core/src/net/socket_addr.rs16
-rw-r--r--library/core/src/num/bignum.rs5
-rw-r--r--library/core/src/num/dec2flt/fpu.rs1
-rw-r--r--library/core/src/num/int_macros.rs18
-rw-r--r--library/core/src/num/mod.rs6
-rw-r--r--library/core/src/num/nonzero.rs9
-rw-r--r--library/core/src/num/uint_macros.rs31
-rw-r--r--library/core/src/option.rs3
-rw-r--r--library/core/src/prelude/mod.rs23
-rw-r--r--library/core/src/primitive_docs.rs28
-rw-r--r--library/core/src/ptr/alignment.rs8
-rw-r--r--library/core/src/ptr/const_ptr.rs26
-rw-r--r--library/core/src/ptr/metadata.rs2
-rw-r--r--library/core/src/ptr/mod.rs30
-rw-r--r--library/core/src/ptr/mut_ptr.rs30
-rw-r--r--library/core/src/ptr/non_null.rs26
-rw-r--r--library/core/src/result.rs8
-rw-r--r--library/core/src/slice/cmp.rs6
-rw-r--r--library/core/src/slice/memchr.rs5
-rw-r--r--library/core/src/slice/mod.rs29
-rw-r--r--library/core/src/slice/raw.rs8
-rw-r--r--library/core/src/slice/rotate.rs6
-rw-r--r--library/core/src/slice/sort/shared/smallsort.rs16
-rw-r--r--library/core/src/slice/sort/stable/mod.rs6
-rw-r--r--library/core/src/slice/sort/stable/quicksort.rs4
-rw-r--r--library/core/src/slice/sort/unstable/quicksort.rs8
-rw-r--r--library/core/src/str/count.rs2
-rw-r--r--library/core/src/str/validations.rs3
-rw-r--r--library/core/src/sync/atomic.rs19
-rw-r--r--library/coretests/benches/ascii/is_ascii.rs6
-rw-r--r--library/coretests/benches/iter.rs5
-rw-r--r--library/coretests/tests/alloc.rs1
-rw-r--r--library/coretests/tests/atomic.rs2
-rw-r--r--library/coretests/tests/hash/sip.rs4
-rw-r--r--library/coretests/tests/nonzero.rs1
-rw-r--r--library/coretests/tests/ptr.rs18
-rw-r--r--library/coretests/tests/slice.rs4
-rw-r--r--library/panic_unwind/src/emcc.rs4
-rw-r--r--library/panic_unwind/src/seh.rs4
-rw-r--r--library/proc_macro/src/bridge/selfless_reify.rs2
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/env.rs3
-rw-r--r--library/std/src/ffi/os_str.rs50
-rw-r--r--library/std/src/fs.rs2
-rw-r--r--library/std/src/fs/tests.rs2
-rw-r--r--library/std/src/io/buffered/bufreader.rs6
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs4
-rw-r--r--library/std/src/io/cursor.rs100
-rw-r--r--library/std/src/io/error/tests.rs1
-rw-r--r--library/std/src/io/impls.rs60
-rw-r--r--library/std/src/keyword_docs.rs9
-rw-r--r--library/std/src/os/fd/tests.rs1
-rw-r--r--library/std/src/os/unix/io/tests.rs1
-rw-r--r--library/std/src/os/unix/net/addr.rs2
-rw-r--r--library/std/src/os/unix/net/listener.rs2
-rw-r--r--library/std/src/os/unix/net/ucred.rs14
-rw-r--r--library/std/src/os/wasi/io/tests.rs1
-rw-r--r--library/std/src/os/windows/io/tests.rs1
-rw-r--r--library/std/src/os/windows/process.rs8
-rw-r--r--library/std/src/os/xous/ffi.rs8
-rw-r--r--library/std/src/os/xous/services/log.rs4
-rw-r--r--library/std/src/prelude/mod.rs15
-rw-r--r--library/std/src/sys/alloc/unix.rs2
-rw-r--r--library/std/src/sys/alloc/windows/tests.rs5
-rw-r--r--library/std/src/sys/fs/common.rs (renamed from library/std/src/sys_common/fs.rs)0
-rw-r--r--library/std/src/sys/fs/hermit.rs (renamed from library/std/src/sys/pal/hermit/fs.rs)20
-rw-r--r--library/std/src/sys/fs/mod.rs28
-rw-r--r--library/std/src/sys/fs/solid.rs (renamed from library/std/src/sys/pal/solid/fs.rs)6
-rw-r--r--library/std/src/sys/fs/uefi.rs (renamed from library/std/src/sys/pal/uefi/fs.rs)0
-rw-r--r--library/std/src/sys/fs/unix.rs (renamed from library/std/src/sys/pal/unix/fs.rs)18
-rw-r--r--library/std/src/sys/fs/unix/tests.rs (renamed from library/std/src/sys/pal/unix/fs/tests.rs)2
-rw-r--r--library/std/src/sys/fs/unsupported.rs (renamed from library/std/src/sys/pal/unsupported/fs.rs)0
-rw-r--r--library/std/src/sys/fs/wasi.rs (renamed from library/std/src/sys/pal/wasi/fs.rs)8
-rw-r--r--library/std/src/sys/fs/windows.rs (renamed from library/std/src/sys/pal/windows/fs.rs)206
-rw-r--r--library/std/src/sys/fs/windows/remove_dir_all.rs (renamed from library/std/src/sys/pal/windows/fs/remove_dir_all.rs)2
-rw-r--r--library/std/src/sys/io/is_terminal/windows.rs1
-rw-r--r--library/std/src/sys/mod.rs2
-rw-r--r--library/std/src/sys/net/connection/socket.rs16
-rw-r--r--library/std/src/sys/net/connection/socket/hermit.rs2
-rw-r--r--library/std/src/sys/net/connection/socket/solid.rs2
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs2
-rw-r--r--library/std/src/sys/net/connection/socket/wasip2.rs2
-rw-r--r--library/std/src/sys/net/connection/socket/windows.rs10
-rw-r--r--library/std/src/sys/net/connection/xous/udp.rs2
-rw-r--r--library/std/src/sys/os_str/bytes.rs5
-rw-r--r--library/std/src/sys/os_str/wtf8.rs5
-rw-r--r--library/std/src/sys/pal/hermit/fd.rs36
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs2
-rw-r--r--library/std/src/sys/pal/hermit/stdio.rs97
-rw-r--r--library/std/src/sys/pal/itron/thread.rs2
-rw-r--r--library/std/src/sys/pal/sgx/abi/mod.rs2
-rw-r--r--library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs42
-rw-r--r--library/std/src/sys/pal/sgx/libunwind_integration.rs12
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs3
-rw-r--r--library/std/src/sys/pal/solid/mod.rs2
-rw-r--r--library/std/src/sys/pal/solid/time.rs2
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs3
-rw-r--r--library/std/src/sys/pal/uefi/args.rs1
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs2
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs2
-rw-r--r--library/std/src/sys/pal/uefi/process.rs2
-rw-r--r--library/std/src/sys/pal/uefi/tests.rs2
-rw-r--r--library/std/src/sys/pal/unix/futex.rs2
-rw-r--r--library/std/src/sys/pal/unix/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/process/process_common.rs5
-rw-r--r--library/std/src/sys/pal/unix/process/process_fuchsia.rs4
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs8
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs2
-rw-r--r--library/std/src/sys/pal/unix/thread.rs6
-rw-r--r--library/std/src/sys/pal/unix/weak.rs2
-rw-r--r--library/std/src/sys/pal/unsupported/mod.rs2
-rw-r--r--library/std/src/sys/pal/wasi/fd.rs8
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs2
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs7
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs4
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs4
-rw-r--r--library/std/src/sys/pal/windows/api.rs4
-rw-r--r--library/std/src/sys/pal/windows/c.rs17
-rw-r--r--library/std/src/sys/pal/windows/futex.rs4
-rw-r--r--library/std/src/sys/pal/windows/mod.rs4
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs2
-rw-r--r--library/std/src/sys/pal/windows/process.rs8
-rw-r--r--library/std/src/sys/pal/xous/mod.rs3
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs5
-rw-r--r--library/std/src/sys/personality/dwarf/eh.rs5
-rw-r--r--library/std/src/sys/personality/dwarf/mod.rs4
-rw-r--r--library/std/src/sys/stdio/mod.rs38
-rw-r--r--library/std/src/sys/stdio/sgx.rs (renamed from library/std/src/sys/pal/sgx/stdio.rs)20
-rw-r--r--library/std/src/sys/stdio/solid.rs (renamed from library/std/src/sys/pal/solid/stdio.rs)2
-rw-r--r--library/std/src/sys/stdio/teeos.rs (renamed from library/std/src/sys/pal/teeos/stdio.rs)0
-rw-r--r--library/std/src/sys/stdio/uefi.rs (renamed from library/std/src/sys/pal/uefi/stdio.rs)0
-rw-r--r--library/std/src/sys/stdio/unix.rs (renamed from library/std/src/sys/pal/unix/stdio.rs)28
-rw-r--r--library/std/src/sys/stdio/unsupported.rs (renamed from library/std/src/sys/pal/unsupported/stdio.rs)0
-rw-r--r--library/std/src/sys/stdio/wasi.rs (renamed from library/std/src/sys/pal/wasi/stdio.rs)2
-rw-r--r--library/std/src/sys/stdio/windows.rs (renamed from library/std/src/sys/pal/windows/stdio.rs)4
-rw-r--r--library/std/src/sys/stdio/windows/tests.rs (renamed from library/std/src/sys/pal/windows/stdio/tests.rs)0
-rw-r--r--library/std/src/sys/stdio/xous.rs (renamed from library/std/src/sys/pal/xous/stdio.rs)2
-rw-r--r--library/std/src/sys/stdio/zkvm.rs (renamed from library/std/src/sys/pal/zkvm/stdio.rs)3
-rw-r--r--library/std/src/sys/thread_local/key/xous.rs11
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/thread/tests.rs4
-rw-r--r--library/unwind/src/unwinding.rs6
-rw-r--r--library/windows_targets/src/lib.rs2
-rw-r--r--src/bootstrap/mk/Makefile.in2
-rw-r--r--src/bootstrap/src/bin/main.rs13
-rw-r--r--src/bootstrap/src/bin/rustc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs5
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs13
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs25
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs12
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs56
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs2
-rw-r--r--src/bootstrap/src/core/builder/mod.rs19
-rw-r--r--src/bootstrap/src/core/builder/tests.rs34
-rw-r--r--src/bootstrap/src/lib.rs4
-rw-r--r--src/bootstrap/src/utils/job.rs4
-rw-r--r--src/build_helper/src/git.rs2
-rw-r--r--src/build_helper/src/metrics.rs2
-rw-r--r--src/ci/citool/src/main.rs20
-rw-r--r--src/ci/citool/src/merge_report.rs257
-rw-r--r--src/ci/citool/src/metrics.rs32
-rw-r--r--src/ci/github-actions/jobs.yml2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/compiletest.md4
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/unstable-book/src/language-features/default-field-values.md2
-rw-r--r--src/doc/unstable-book/src/language-features/rustc-private.md30
-rw-r--r--src/etc/test-float-parse/Cargo.toml4
-rw-r--r--src/etc/test-float-parse/src/gen/fuzz.rs8
-rw-r--r--src/etc/test-float-parse/src/gen/many_digits.rs14
-rw-r--r--src/etc/test-float-parse/src/lib.rs4
-rw-r--r--src/librustdoc/clean/inline.rs10
-rw-r--r--src/librustdoc/clean/mod.rs117
-rw-r--r--src/librustdoc/clean/types.rs38
-rw-r--r--src/librustdoc/clean/utils.rs6
-rw-r--r--src/librustdoc/config.rs16
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/librustdoc/display.rs2
-rw-r--r--src/librustdoc/doctest.rs172
-rw-r--r--src/librustdoc/doctest/extracted.rs4
-rw-r--r--src/librustdoc/doctest/runner.rs56
-rw-r--r--src/librustdoc/doctest/rust.rs5
-rw-r--r--src/librustdoc/formats/cache.rs4
-rw-r--r--src/librustdoc/html/format.rs12
-rw-r--r--src/librustdoc/html/highlight.rs91
-rw-r--r--src/librustdoc/html/markdown.rs17
-rw-r--r--src/librustdoc/html/render/print_item.rs18
-rw-r--r--src/librustdoc/html/render/search_index.rs5
-rw-r--r--src/librustdoc/html/render/search_index/encode.rs4
-rw-r--r--src/librustdoc/html/render/sidebar.rs18
-rw-r--r--src/librustdoc/html/render/span_map.rs24
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs59
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs33
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs6
-rw-r--r--src/librustdoc/passes/lint/unportable_markdown.rs16
-rw-r--r--src/librustdoc/passes/propagate_stability.rs6
-rw-r--r--src/librustdoc/visit_lib.rs8
-rw-r--r--src/tools/build-manifest/src/main.rs1
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs3
-rw-r--r--src/tools/compiletest/src/raise_fd_limit.rs1
-rw-r--r--src/tools/compiletest/src/runtest/crashes.rs2
-rw-r--r--src/tools/compiletest/src/runtest/run_make.rs5
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/tests/fail/shims/fs/isolated_file.stderr18
-rw-r--r--src/tools/miri/tests/ui.rs4
-rw-r--r--src/tools/run-make-support/Cargo.toml4
-rw-r--r--src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs16
-rw-r--r--src/tools/run-make-support/src/lib.rs4
-rw-r--r--src/tools/run-make-support/src/targets.rs6
-rw-r--r--src/tools/rust-analyzer/.editorconfig3
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml73
-rw-r--r--src/tools/rust-analyzer/Cargo.lock45
-rw-r--r--src/tools/rust-analyzer/Cargo.toml20
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs19
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/dnf.rs19
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/lib.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs166
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs68
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs109
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs194
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs57
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs39
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/has_source.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs214
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs (renamed from src/tools/rust-analyzer/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs)23
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs (renamed from src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs)96
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs (renamed from src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs)205
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs118
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs (renamed from src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs)36
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs169
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs44
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs119
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs93
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/source_change.rs45
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs54
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs124
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs39
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/interpret.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs61
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs81
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/ssr.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs138
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs353
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html33
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html21
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html94
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs75
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs20
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol.rs31
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/tests.rs17
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs2
-rw-r--r--src/tools/rust-analyzer/crates/profile/src/memory_usage.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs18
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs137
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs64
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt501
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt454
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs43
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs56
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs26
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs121
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs113
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs56
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs10
-rw-r--r--src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs70
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs50
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs63
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs21
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation.rs36
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rast25
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast23
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast25
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rs1
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs7
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs30
-rw-r--r--src/tools/rust-analyzer/docs/book/src/assists_generated.md206
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md4
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json2
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts1
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts6
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts19
-rw-r--r--src/tools/rust-analyzer/editors/code/src/util.ts4
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rustfmt/src/expr.rs4
-rw-r--r--src/tools/rustfmt/src/utils.rs1
-rw-r--r--src/tools/tidy/Cargo.toml1
-rw-r--r--src/tools/tidy/src/deps.rs41
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/style.rs2
-rw-r--r--src/tools/tidy/src/triagebot.rs93
-rw-r--r--tests/assembly/stack-protector/stack-protector-target-support.rs6
-rw-r--r--tests/assembly/targets/targets-pe.rs3
-rw-r--r--tests/codegen/asm/critical.rs37
-rw-r--r--tests/codegen/enum/enum-two-variants-match.rs51
-rw-r--r--tests/codegen/intrinsics/cold_path2.rs3
-rw-r--r--tests/codegen/intrinsics/transmute.rs25
-rw-r--r--tests/codegen/issues/auxiliary/static_dllimport_aux.rs13
-rw-r--r--tests/codegen/issues/issue-101082.rs1
-rw-r--r--tests/codegen/issues/issue-122600-ptr-discriminant-update.rs29
-rw-r--r--tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs15
-rw-r--r--tests/codegen/target-feature-inline-closure.rs8
-rw-r--r--tests/codegen/try_question_mark_nop.rs8
-rw-r--r--tests/crashes/127916.rs16
-rw-r--r--tests/crashes/128119.rs15
-rw-r--r--tests/crashes/128190.rs7
-rw-r--r--tests/crashes/133426.rs12
-rw-r--r--tests/crashes/136138.rs7
-rw-r--r--tests/crashes/136175-2.rs13
-rw-r--r--tests/crashes/136175.rs13
-rw-r--r--tests/crashes/136188.rs9
-rw-r--r--tests/crashes/136286.rs7
-rw-r--r--tests/crashes/136379.rs11
-rw-r--r--tests/crashes/136381.rs18
-rw-r--r--tests/crashes/136416.rs6
-rw-r--r--tests/crashes/136442.rs9
-rw-r--r--tests/crashes/136661.rs25
-rw-r--r--tests/crashes/136666.rs36
-rw-r--r--tests/crashes/136678.rs18
-rw-r--r--tests/crashes/136766.rs6
-rw-r--r--tests/crashes/136859.rs27
-rw-r--r--tests/crashes/136894.rs8
-rw-r--r--tests/crashes/137049.rs29
-rw-r--r--tests/crashes/137084.rs6
-rw-r--r--tests/crashes/137187.rs9
-rw-r--r--tests/crashes/137188.rs6
-rw-r--r--tests/crashes/137190-1.rs10
-rw-r--r--tests/crashes/137190-2.rs18
-rw-r--r--tests/crashes/137190-3.rs10
-rw-r--r--tests/crashes/137260.rs11
-rw-r--r--tests/crashes/137287.rs29
-rw-r--r--tests/crashes/137467-1.rs17
-rw-r--r--tests/crashes/137467-2.rs18
-rw-r--r--tests/crashes/137467-3.rs8
-rw-r--r--tests/crashes/137468.rs16
-rw-r--r--tests/crashes/137514.rs9
-rw-r--r--tests/crashes/137580.rs4
-rw-r--r--tests/crashes/137582.rs16
-rw-r--r--tests/crashes/137706.rs7
-rw-r--r--tests/crashes/137751.rs6
-rw-r--r--tests/crashes/137813.rs18
-rw-r--r--tests/crashes/137865.rs5
-rw-r--r--tests/crashes/137874.rs4
-rw-r--r--tests/crashes/137888.rs11
-rw-r--r--tests/crashes/137895.rs6
-rw-r--r--tests/crashes/137916.rs13
-rw-r--r--tests/crashes/138008.rs8
-rw-r--r--tests/crashes/138009.rs6
-rw-r--r--tests/crashes/138048.rs8
-rw-r--r--tests/crashes/138088.rs5
-rw-r--r--tests/crashes/138089.rs13
-rw-r--r--tests/crashes/138131.rs12
-rw-r--r--tests/crashes/138132.rs10
-rw-r--r--tests/crashes/138166.rs8
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir89
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.rs26
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir4
-rw-r--r--tests/run-make/broken-pipe-no-ice/rmake.rs8
-rw-r--r--tests/run-make/cross-lang-lto/rmake.rs15
-rw-r--r--tests/run-make/doctests-merge/rmake.rs1
-rw-r--r--tests/run-make/issue-107495-archive-permissions/rmake.rs7
-rw-r--r--tests/run-make/repr128-dwarf/rmake.rs15
-rw-r--r--tests/run-make/unstable-feature-usage-metrics/rmake.rs11
-rw-r--r--tests/rustdoc-json/attrs/export_name_2021.rs6
-rw-r--r--tests/rustdoc-json/attrs/export_name_2024.rs9
-rw-r--r--tests/rustdoc-json/attrs/must_use.rs9
-rw-r--r--tests/rustdoc-json/attrs/no_mangle_2021.rs6
-rw-r--r--tests/rustdoc-json/attrs/no_mangle_2024.rs9
-rw-r--r--tests/rustdoc-json/attrs/non_exhaustive.rs19
-rw-r--r--tests/rustdoc-ui/diagnostic-width.stderr4
-rw-r--r--tests/rustdoc-ui/doctest/doctest-output.rs2
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout28
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout25
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs17
-rw-r--r--tests/ui-fulldeps/hash-stable-is-unstable.rs1
-rw-r--r--tests/ui-fulldeps/hash-stable-is-unstable.stderr10
-rw-r--r--tests/ui-fulldeps/pathless-extern-unstable.rs1
-rw-r--r--tests/ui-fulldeps/pathless-extern-unstable.stderr2
-rw-r--r--tests/ui/asm/global-asm-isnt-really-a-mir-body.rs26
-rw-r--r--tests/ui/asm/global-asm-with-error.rs11
-rw-r--r--tests/ui/asm/global-asm-with-error.stderr9
-rw-r--r--tests/ui/asm/invalid-const-operand.rs8
-rw-r--r--tests/ui/asm/invalid-const-operand.stderr8
-rw-r--r--tests/ui/asm/tainting-on-error.rs13
-rw-r--r--tests/ui/asm/tainting-on-error.stderr10
-rw-r--r--tests/ui/asm/x86_64/type-check-2.rs8
-rw-r--r--tests/ui/asm/x86_64/type-check-2.stderr16
-rw-r--r--tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr3
-rw-r--r--tests/ui/auto-traits/ungated-impl.rs7
-rw-r--r--tests/ui/auto-traits/ungated-impl.stderr23
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs36
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr48
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs36
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr43
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs41
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr140
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap.rs33
-rw-r--r--tests/ui/check-cfg/allow-same-level.rs2
-rw-r--r--tests/ui/codemap_tests/tab_2.stderr2
-rw-r--r--tests/ui/consts/issue-94675.rs2
-rw-r--r--tests/ui/coroutine/gen_block.e2024.stderr22
-rw-r--r--tests/ui/coroutine/gen_block.none.stderr4
-rw-r--r--tests/ui/coroutine/gen_block.rs4
-rw-r--r--tests/ui/delegation/ice-isssue-128190.rs9
-rw-r--r--tests/ui/delegation/ice-isssue-128190.stderr10
-rw-r--r--tests/ui/diagnostic-width/long-span.long.stderr18
-rw-r--r--tests/ui/diagnostic-width/long-span.longest.stderr18
-rw-r--r--tests/ui/diagnostic-width/long-span.rs11
-rw-r--r--tests/ui/diagnostic-width/long-span.short.stderr18
-rw-r--r--tests/ui/diagnostic-width/long-span.shortest.stderr18
-rw-r--r--tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr59
-rw-r--r--tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs6
-rw-r--r--tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr59
-rw-r--r--tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr8
-rw-r--r--tests/ui/diagnostic-width/tabs-trimming.stderr20
-rw-r--r--tests/ui/dyn-keyword/dyn-2021-edition-error.rs6
-rw-r--r--tests/ui/dyn-keyword/dyn-2021-edition-error.stderr13
-rw-r--r--tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.rs41
-rw-r--r--tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.stderr74
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.stderr8
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.stderr16
-rw-r--r--tests/ui/ergonomic-clones/async/basic.rs17
-rw-r--r--tests/ui/ergonomic-clones/async/edition-2015.rs7
-rw-r--r--tests/ui/ergonomic-clones/async/edition-2015.stderr8
-rw-r--r--tests/ui/ergonomic-clones/async/local-type.rs10
-rw-r--r--tests/ui/ergonomic-clones/async/local-type.stderr15
-rw-r--r--tests/ui/ergonomic-clones/closure/basic.rs58
-rw-r--r--tests/ui/ergonomic-clones/closure/const-closure.rs11
-rw-r--r--tests/ui/ergonomic-clones/closure/expect-region.rs25
-rw-r--r--tests/ui/ergonomic-clones/closure/expect-region.stderr22
-rw-r--r--tests/ui/ergonomic-clones/closure/fn-once.rs14
-rw-r--r--tests/ui/ergonomic-clones/closure/fn-once.stderr16
-rw-r--r--tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed16
-rw-r--r--tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs16
-rw-r--r--tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr14
-rw-r--r--tests/ui/ergonomic-clones/closure/local-type.rs9
-rw-r--r--tests/ui/ergonomic-clones/closure/local-type.stderr15
-rw-r--r--tests/ui/ergonomic-clones/closure/mutation.rs12
-rw-r--r--tests/ui/ergonomic-clones/closure/mutation2.rs11
-rw-r--r--tests/ui/ergonomic-clones/closure/mutation2.stderr17
-rw-r--r--tests/ui/ergonomic-clones/closure/nested.rs21
-rw-r--r--tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs19
-rw-r--r--tests/ui/ergonomic-clones/closure/parse.rs22
-rw-r--r--tests/ui/ergonomic-clones/closure/parse.stderr28
-rw-r--r--tests/ui/ergonomic-clones/closure/print-verbose.rs28
-rw-r--r--tests/ui/ergonomic-clones/closure/print-verbose.stderr20
-rw-r--r--tests/ui/ergonomic-clones/closure/print.rs26
-rw-r--r--tests/ui/ergonomic-clones/closure/print.stderr20
-rw-r--r--tests/ui/ergonomic-clones/closure/with-binders.rs10
-rw-r--r--tests/ui/ergonomic-clones/dotuse/basic.rs22
-rw-r--r--tests/ui/ergonomic-clones/dotuse/parse.rs39
-rw-r--r--tests/ui/ergonomic-clones/dotuse/parse.stderr53
-rw-r--r--tests/ui/error-codes/E0582.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-coroutines.none.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-ergonomic-clones.rs32
-rw-r--r--tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr63
-rw-r--r--tests/ui/feature-gates/feature-gate-yield-expr.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-yield-expr.stderr41
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr2
-rw-r--r--tests/ui/issues/issue-44078.stderr2
-rw-r--r--tests/ui/layout/post-mono-layout-cycle-2.rs2
-rw-r--r--tests/ui/layout/post-mono-layout-cycle-2.stderr6
-rw-r--r--tests/ui/lexer/unterminated-nested-comment.stderr2
-rw-r--r--tests/ui/lifetimes/static-typos.rs7
-rw-r--r--tests/ui/lifetimes/static-typos.stderr26
-rw-r--r--tests/ui/linking/no-gc-encapsulation-symbols.rs25
-rw-r--r--tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs4
-rw-r--r--tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs2
-rw-r--r--tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs2
-rw-r--r--tests/ui/lint/lint-incoherent-auto-trait-objects.rs3
-rw-r--r--tests/ui/lint/lint-incoherent-auto-trait-objects.stderr65
-rw-r--r--tests/ui/lint/unused/must-use-ops.rs2
-rw-r--r--tests/ui/lowering/no-name-for-DefPath-issue-133426.rs20
-rw-r--r--tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr31
-rw-r--r--tests/ui/macros/not-utf8.stderr2
-rw-r--r--tests/ui/macros/same-sequence-span.stderr2
-rw-r--r--tests/ui/nll/issue-97997.rs1
-rw-r--r--tests/ui/nll/issue-97997.stderr12
-rw-r--r--tests/ui/parser/block-no-opening-brace.rs2
-rw-r--r--tests/ui/parser/block-no-opening-brace.stderr4
-rw-r--r--tests/ui/parser/byte-string-literals.stderr2
-rw-r--r--tests/ui/parser/misspelled-keywords/async-move.stderr4
-rw-r--r--tests/ui/parser/raw/too-many-hash.stderr4
-rw-r--r--tests/ui/parser/recover/recover-quantified-closure.rs2
-rw-r--r--tests/ui/parser/recover/recover-quantified-closure.stderr4
-rw-r--r--tests/ui/parser/unbalanced-doublequote.stderr2
-rw-r--r--tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr2
-rw-r--r--tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs2
-rw-r--r--tests/ui/repr/repr-empty-packed.rs9
-rw-r--r--tests/ui/repr/repr-empty-packed.stderr27
-rw-r--r--tests/ui/rust-2024/reserved-guarded-strings.stderr2
-rw-r--r--tests/ui/traits/issue-33140-hack-boundaries.rs2
-rw-r--r--tests/ui/traits/issue-33140-hack-boundaries.stderr22
-rw-r--r--tests/ui/traits/object/issue-33140-traitobject-crate.rs12
-rw-r--r--tests/ui/traits/object/issue-33140-traitobject-crate.stderr86
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr2
-rw-r--r--tests/ui/typeck/issue-84768.stderr2
-rw-r--r--tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr4
-rw-r--r--tests/ui/unpretty/deprecated-attr.rs2
-rw-r--r--tests/ui/unpretty/deprecated-attr.stdout17
-rw-r--r--triagebot.toml26
923 files changed, 13360 insertions, 6511 deletions
diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml
new file mode 100644
index 00000000000..2bc06d83c5b
--- /dev/null
+++ b/.github/workflows/post-merge.yml
@@ -0,0 +1,42 @@
+# Workflow that runs after a merge to master, analyses changes in test executions
+# and posts the result to the merged PR.
+
+name: Post merge analysis
+
+on:
+  push:
+    branches:
+      - master
+
+jobs:
+  analysis:
+    runs-on: ubuntu-24.04
+    if: github.repository == 'rust-lang/rust'
+    permissions:
+      pull-requests: write
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          # Make sure that we have enough commits to find the parent merge commit.
+          # Since all merges should be through merge commits, fetching two commits
+          # should be enough to get the parent bors merge commit.
+          fetch-depth: 2
+      - name: Perform analysis and send PR
+        env:
+          GH_TOKEN: ${{ github.token }}
+        run: |
+          # Get closest bors merge commit
+          PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
+          echo "Parent: ${PARENT_COMMIT}"
+
+          # Find PR for the current commit
+          HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'`
+          echo "HEAD: ${{ github.sha }} (#${HEAD_PR})"
+
+          cd src/ci/citool
+
+          echo "Post-merge analysis result" > output.log
+          cargo run --release post-merge-analysis ${PARENT_COMMIT} ${{ github.sha }} >> output.log
+          cat output.log
+
+          gh pr comment ${HEAD_PR} -F output.log
diff --git a/.gitignore b/.gitignore
index 2184e04f16b..b8cb31e8190 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,7 @@ no_llvm_build
 /target
 /library/target
 /src/bootstrap/target
+/src/ci/citool/target
 /src/tools/x/target
 # Created by `x vendor`
 /vendor
diff --git a/Cargo.lock b/Cargo.lock
index 72f2d4f6cd3..ea93fbd01f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2527,6 +2527,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
+name = "os_pipe"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
 name = "overload"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2871,11 +2881,11 @@ dependencies = [
 
 [[package]]
 name = "rand_xoshiro"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
+checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core 0.9.0",
 ]
 
 [[package]]
@@ -3050,6 +3060,7 @@ dependencies = [
  "gimli 0.31.1",
  "libc",
  "object 0.36.7",
+ "os_pipe",
  "regex",
  "serde_json",
  "similar",
@@ -3144,7 +3155,7 @@ name = "rustc_abi"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "rand 0.8.5",
+ "rand 0.9.0",
  "rand_xoshiro",
  "rustc_data_structures",
  "rustc_hashes",
@@ -3286,6 +3297,7 @@ dependencies = [
  "rustc_hir",
  "rustc_lexer",
  "rustc_macros",
+ "rustc_middle",
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
@@ -3741,7 +3753,7 @@ dependencies = [
  "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_hir",
  "rustc_span",
 ]
@@ -3777,7 +3789,7 @@ dependencies = [
 name = "rustc_incremental"
 version = "0.0.0"
 dependencies = [
- "rand 0.8.5",
+ "rand 0.9.0",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -4009,7 +4021,8 @@ dependencies = [
  "rustc_apfloat",
  "rustc_arena",
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_ast_ir",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_error_messages",
  "rustc_errors",
@@ -5163,8 +5176,8 @@ version = "0.1.0"
 dependencies = [
  "indicatif",
  "num",
- "rand 0.8.5",
- "rand_chacha 0.3.1",
+ "rand 0.9.0",
+ "rand_chacha 0.9.0",
  "rayon",
 ]
 
@@ -5260,6 +5273,7 @@ dependencies = [
  "serde",
  "similar",
  "termcolor",
+ "toml 0.7.8",
  "walkdir",
 ]
 
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 86dc84e2016..5f9afc46a1a 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -6,13 +6,13 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-rand = { version = "0.8.4", default-features = false, optional = true }
-rand_xoshiro = { version = "0.6.0", optional = true }
-rustc_data_structures = { path = "../rustc_data_structures", optional = true  }
+rand = { version = "0.9.0", default-features = false, optional = true }
+rand_xoshiro = { version = "0.7.0", optional = true }
+rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
-rustc_serialize = { path = "../rustc_serialize", optional = true  }
+rustc_serialize = { path = "../rustc_serialize", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index d3ae6a29f10..7bffeaf4cc9 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -4,6 +4,7 @@ use std::{cmp, iter};
 
 use rustc_hashes::Hash64;
 use rustc_index::Idx;
+use rustc_index::bit_set::BitMatrix;
 use tracing::debug;
 
 use crate::{
@@ -12,6 +13,9 @@ use crate::{
     Variants, WrappingRange,
 };
 
+mod coroutine;
+mod simple;
+
 #[cfg(feature = "nightly")]
 mod ty;
 
@@ -60,17 +64,28 @@ pub enum LayoutCalculatorError<F> {
 
     /// The fields or variants have irreconcilable reprs
     ReprConflict,
+
+    /// The length of an SIMD type is zero
+    ZeroLengthSimdType,
+
+    /// The length of an SIMD type exceeds the maximum number of lanes
+    OversizedSimdType { max_lanes: u64 },
+
+    /// An element type of an SIMD type isn't a primitive
+    NonPrimitiveSimdType(F),
 }
 
 impl<F> LayoutCalculatorError<F> {
     pub fn without_payload(&self) -> LayoutCalculatorError<()> {
-        match self {
-            LayoutCalculatorError::UnexpectedUnsized(_) => {
-                LayoutCalculatorError::UnexpectedUnsized(())
-            }
-            LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow,
-            LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion,
-            LayoutCalculatorError::ReprConflict => LayoutCalculatorError::ReprConflict,
+        use LayoutCalculatorError::*;
+        match *self {
+            UnexpectedUnsized(_) => UnexpectedUnsized(()),
+            SizeOverflow => SizeOverflow,
+            EmptyUnion => EmptyUnion,
+            ReprConflict => ReprConflict,
+            ZeroLengthSimdType => ZeroLengthSimdType,
+            OversizedSimdType { max_lanes } => OversizedSimdType { max_lanes },
+            NonPrimitiveSimdType(_) => NonPrimitiveSimdType(()),
         }
     }
 
@@ -78,13 +93,15 @@ impl<F> LayoutCalculatorError<F> {
     ///
     /// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra.
     pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use LayoutCalculatorError::*;
         f.write_str(match self {
-            LayoutCalculatorError::UnexpectedUnsized(_) => {
-                "an unsized type was found where a sized type was expected"
+            UnexpectedUnsized(_) => "an unsized type was found where a sized type was expected",
+            SizeOverflow => "size overflow",
+            EmptyUnion => "type is a union with no fields",
+            ReprConflict => "type has an invalid repr",
+            ZeroLengthSimdType | OversizedSimdType { .. } | NonPrimitiveSimdType(_) => {
+                "invalid simd type definition"
             }
-            LayoutCalculatorError::SizeOverflow => "size overflow",
-            LayoutCalculatorError::EmptyUnion => "type is a union with no fields",
-            LayoutCalculatorError::ReprConflict => "type has an invalid repr",
         })
     }
 }
@@ -102,41 +119,115 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         Self { cx }
     }
 
-    pub fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(
+    pub fn array_like<FieldIdx: Idx, VariantIdx: Idx, F>(
         &self,
-        a: Scalar,
-        b: Scalar,
-    ) -> LayoutData<FieldIdx, VariantIdx> {
-        let dl = self.cx.data_layout();
-        let b_align = b.align(dl);
-        let align = a.align(dl).max(b_align).max(dl.aggregate_align);
-        let b_offset = a.size(dl).align_to(b_align.abi);
-        let size = (b_offset + b.size(dl)).align_to(align.abi);
+        element: &LayoutData<FieldIdx, VariantIdx>,
+        count_if_sized: Option<u64>, // None for slices
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
+        let count = count_if_sized.unwrap_or(0);
+        let size =
+            element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?;
 
-        // HACK(nox): We iter on `b` and then `a` because `max_by_key`
-        // returns the last maximum.
-        let largest_niche = Niche::from_scalar(dl, b_offset, b)
-            .into_iter()
-            .chain(Niche::from_scalar(dl, Size::ZERO, a))
-            .max_by_key(|niche| niche.available(dl));
+        Ok(LayoutData {
+            variants: Variants::Single { index: VariantIdx::new(0) },
+            fields: FieldsShape::Array { stride: element.size, count },
+            backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() },
+            largest_niche: element.largest_niche.filter(|_| count != 0),
+            uninhabited: element.uninhabited && count != 0,
+            align: element.align,
+            size,
+            max_repr_align: None,
+            unadjusted_abi_align: element.align.abi,
+            randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
+        })
+    }
 
-        let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes());
+    pub fn simd_type<
+        FieldIdx: Idx,
+        VariantIdx: Idx,
+        F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
+    >(
+        &self,
+        element: F,
+        count: u64,
+        repr_packed: bool,
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
+        let elt = element.as_ref();
+        if count == 0 {
+            return Err(LayoutCalculatorError::ZeroLengthSimdType);
+        } else if count > crate::MAX_SIMD_LANES {
+            return Err(LayoutCalculatorError::OversizedSimdType {
+                max_lanes: crate::MAX_SIMD_LANES,
+            });
+        }
 
-        LayoutData {
+        let BackendRepr::Scalar(e_repr) = elt.backend_repr else {
+            return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
+        };
+
+        // Compute the size and alignment of the vector
+        let dl = self.cx.data_layout();
+        let size =
+            elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
+        let (repr, align) = if repr_packed && !count.is_power_of_two() {
+            // Non-power-of-two vectors have padding up to the next power-of-two.
+            // If we're a packed repr, remove the padding while keeping the alignment as close
+            // to a vector as possible.
+            (
+                BackendRepr::Memory { sized: true },
+                AbiAndPrefAlign {
+                    abi: Align::max_aligned_factor(size),
+                    pref: dl.llvmlike_vector_align(size).pref,
+                },
+            )
+        } else {
+            (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
+        };
+        let size = size.align_to(align.abi);
+
+        Ok(LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary {
-                offsets: [Size::ZERO, b_offset].into(),
-                memory_index: [0, 1].into(),
+                offsets: [Size::ZERO].into(),
+                memory_index: [0].into(),
             },
-            backend_repr: BackendRepr::ScalarPair(a, b),
-            largest_niche,
+            backend_repr: repr,
+            largest_niche: elt.largest_niche,
             uninhabited: false,
-            align,
             size,
+            align,
             max_repr_align: None,
-            unadjusted_abi_align: align.abi,
-            randomization_seed: Hash64::new(combined_seed),
-        }
+            unadjusted_abi_align: elt.align.abi,
+            randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
+        })
+    }
+
+    /// Compute the layout for a coroutine.
+    ///
+    /// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine
+    /// fields may be shared between multiple variants (see the [`coroutine`] module for details).
+    pub fn coroutine<
+        'a,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        VariantIdx: Idx,
+        FieldIdx: Idx,
+        LocalIdx: Idx,
+    >(
+        &self,
+        local_layouts: &IndexSlice<LocalIdx, F>,
+        prefix_layouts: IndexVec<FieldIdx, F>,
+        variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>,
+        storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>,
+        tag_to_layout: impl Fn(Scalar) -> F,
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
+        coroutine::layout(
+            self,
+            local_layouts,
+            prefix_layouts,
+            variant_fields,
+            storage_conflicts,
+            tag_to_layout,
+        )
     }
 
     pub fn univariant<
@@ -214,25 +305,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         layout
     }
 
-    pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>(
-        &self,
-    ) -> LayoutData<FieldIdx, VariantIdx> {
-        let dl = self.cx.data_layout();
-        // This is also used for uninhabited enums, so we use `Variants::Empty`.
-        LayoutData {
-            variants: Variants::Empty,
-            fields: FieldsShape::Primitive,
-            backend_repr: BackendRepr::Memory { sized: true },
-            largest_niche: None,
-            uninhabited: true,
-            align: dl.i8_align,
-            size: Size::ZERO,
-            max_repr_align: None,
-            unadjusted_abi_align: dl.i8_align.abi,
-            randomization_seed: Hash64::ZERO,
-        }
-    }
-
     pub fn layout_of_struct_or_enum<
         'a,
         FieldIdx: Idx,
@@ -260,7 +332,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             Some(present_first) => present_first,
             // Uninhabited because it has no variants, or only absent ones.
             None if is_enum => {
-                return Ok(self.layout_of_never_type());
+                return Ok(LayoutData::never_type(&self.cx));
             }
             // If it's a struct, still compute a layout so that we can still compute the
             // field offsets.
@@ -949,7 +1021,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                     // Common prim might be uninit.
                     Scalar::Union { value: prim }
                 };
-                let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar);
+                let pair =
+                    LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
                 let pair_offsets = match pair.fields {
                     FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                         assert_eq!(memory_index.raw, [0, 1]);
@@ -1341,7 +1414,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                             } else {
                                 ((j, b), (i, a))
                             };
-                            let pair = self.scalar_pair::<FieldIdx, VariantIdx>(a, b);
+                            let pair =
+                                LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
                             let pair_offsets = match pair.fields {
                                 FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                                     assert_eq!(memory_index.raw, [0, 1]);
diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs
new file mode 100644
index 00000000000..27e704d538c
--- /dev/null
+++ b/compiler/rustc_abi/src/layout/coroutine.rs
@@ -0,0 +1,320 @@
+//! Coroutine layout logic.
+//!
+//! When laying out coroutines, we divide our saved local fields into two
+//! categories: overlap-eligible and overlap-ineligible.
+//!
+//! Those fields which are ineligible for overlap go in a "prefix" at the
+//! beginning of the layout, and always have space reserved for them.
+//!
+//! Overlap-eligible fields are only assigned to one variant, so we lay
+//! those fields out for each variant and put them right after the
+//! prefix.
+//!
+//! Finally, in the layout details, we point to the fields from the
+//! variants they are assigned to. It is possible for some fields to be
+//! included in multiple variants. No field ever "moves around" in the
+//! layout; its offset is always the same.
+//!
+//! Also included in the layout are the upvars and the discriminant.
+//! These are included as fields on the "outer" layout; they are not part
+//! of any variant.
+
+use std::iter;
+
+use rustc_index::bit_set::{BitMatrix, DenseBitSet};
+use rustc_index::{Idx, IndexSlice, IndexVec};
+use tracing::{debug, trace};
+
+use crate::{
+    BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutData, Primitive, ReprOptions, Scalar,
+    StructKind, TagEncoding, Variants, WrappingRange,
+};
+
+/// Overlap eligibility and variant assignment for each CoroutineSavedLocal.
+#[derive(Clone, Debug, PartialEq)]
+enum SavedLocalEligibility<VariantIdx, FieldIdx> {
+    Unassigned,
+    Assigned(VariantIdx),
+    Ineligible(Option<FieldIdx>),
+}
+
+/// Compute the eligibility and assignment of each local.
+fn coroutine_saved_local_eligibility<VariantIdx: Idx, FieldIdx: Idx, LocalIdx: Idx>(
+    nb_locals: usize,
+    variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>,
+    storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>,
+) -> (DenseBitSet<LocalIdx>, IndexVec<LocalIdx, SavedLocalEligibility<VariantIdx, FieldIdx>>) {
+    use SavedLocalEligibility::*;
+
+    let mut assignments: IndexVec<LocalIdx, _> = IndexVec::from_elem_n(Unassigned, nb_locals);
+
+    // The saved locals not eligible for overlap. These will get
+    // "promoted" to the prefix of our coroutine.
+    let mut ineligible_locals = DenseBitSet::new_empty(nb_locals);
+
+    // Figure out which of our saved locals are fields in only
+    // one variant. The rest are deemed ineligible for overlap.
+    for (variant_index, fields) in variant_fields.iter_enumerated() {
+        for local in fields {
+            match assignments[*local] {
+                Unassigned => {
+                    assignments[*local] = Assigned(variant_index);
+                }
+                Assigned(idx) => {
+                    // We've already seen this local at another suspension
+                    // point, so it is no longer a candidate.
+                    trace!(
+                        "removing local {:?} in >1 variant ({:?}, {:?})",
+                        local, variant_index, idx
+                    );
+                    ineligible_locals.insert(*local);
+                    assignments[*local] = Ineligible(None);
+                }
+                Ineligible(_) => {}
+            }
+        }
+    }
+
+    // Next, check every pair of eligible locals to see if they
+    // conflict.
+    for local_a in storage_conflicts.rows() {
+        let conflicts_a = storage_conflicts.count(local_a);
+        if ineligible_locals.contains(local_a) {
+            continue;
+        }
+
+        for local_b in storage_conflicts.iter(local_a) {
+            // local_a and local_b are storage live at the same time, therefore they
+            // cannot overlap in the coroutine layout. The only way to guarantee
+            // this is if they are in the same variant, or one is ineligible
+            // (which means it is stored in every variant).
+            if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] {
+                continue;
+            }
+
+            // If they conflict, we will choose one to make ineligible.
+            // This is not always optimal; it's just a greedy heuristic that
+            // seems to produce good results most of the time.
+            let conflicts_b = storage_conflicts.count(local_b);
+            let (remove, other) =
+                if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) };
+            ineligible_locals.insert(remove);
+            assignments[remove] = Ineligible(None);
+            trace!("removing local {:?} due to conflict with {:?}", remove, other);
+        }
+    }
+
+    // Count the number of variants in use. If only one of them, then it is
+    // impossible to overlap any locals in our layout. In this case it's
+    // always better to make the remaining locals ineligible, so we can
+    // lay them out with the other locals in the prefix and eliminate
+    // unnecessary padding bytes.
+    {
+        let mut used_variants = DenseBitSet::new_empty(variant_fields.len());
+        for assignment in &assignments {
+            if let Assigned(idx) = assignment {
+                used_variants.insert(*idx);
+            }
+        }
+        if used_variants.count() < 2 {
+            for assignment in assignments.iter_mut() {
+                *assignment = Ineligible(None);
+            }
+            ineligible_locals.insert_all();
+        }
+    }
+
+    // Write down the order of our locals that will be promoted to the prefix.
+    {
+        for (idx, local) in ineligible_locals.iter().enumerate() {
+            assignments[local] = Ineligible(Some(FieldIdx::new(idx)));
+        }
+    }
+    debug!("coroutine saved local assignments: {:?}", assignments);
+
+    (ineligible_locals, assignments)
+}
+
+/// Compute the full coroutine layout.
+pub(super) fn layout<
+    'a,
+    F: core::ops::Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + core::fmt::Debug + Copy,
+    VariantIdx: Idx,
+    FieldIdx: Idx,
+    LocalIdx: Idx,
+>(
+    calc: &super::LayoutCalculator<impl HasDataLayout>,
+    local_layouts: &IndexSlice<LocalIdx, F>,
+    mut prefix_layouts: IndexVec<FieldIdx, F>,
+    variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>,
+    storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>,
+    tag_to_layout: impl Fn(Scalar) -> F,
+) -> super::LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
+    use SavedLocalEligibility::*;
+
+    let (ineligible_locals, assignments) =
+        coroutine_saved_local_eligibility(local_layouts.len(), variant_fields, storage_conflicts);
+
+    // Build a prefix layout, including "promoting" all ineligible
+    // locals as part of the prefix. We compute the layout of all of
+    // these fields at once to get optimal packing.
+    let tag_index = prefix_layouts.len();
+
+    // `variant_fields` already accounts for the reserved variants, so no need to add them.
+    let max_discr = (variant_fields.len() - 1) as u128;
+    let discr_int = Integer::fit_unsigned(max_discr);
+    let tag = Scalar::Initialized {
+        value: Primitive::Int(discr_int, /* signed = */ false),
+        valid_range: WrappingRange { start: 0, end: max_discr },
+    };
+
+    let promoted_layouts = ineligible_locals.iter().map(|local| local_layouts[local]);
+    prefix_layouts.push(tag_to_layout(tag));
+    prefix_layouts.extend(promoted_layouts);
+    let prefix =
+        calc.univariant(&prefix_layouts, &ReprOptions::default(), StructKind::AlwaysSized)?;
+
+    let (prefix_size, prefix_align) = (prefix.size, prefix.align);
+
+    // Split the prefix layout into the "outer" fields (upvars and
+    // discriminant) and the "promoted" fields. Promoted fields will
+    // get included in each variant that requested them in
+    // CoroutineLayout.
+    debug!("prefix = {:#?}", prefix);
+    let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
+        FieldsShape::Arbitrary { mut offsets, memory_index } => {
+            let mut inverse_memory_index = memory_index.invert_bijective_mapping();
+
+            // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
+            // "outer" and "promoted" fields respectively.
+            let b_start = FieldIdx::new(tag_index + 1);
+            let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index()));
+            let offsets_a = offsets;
+
+            // Disentangle the "a" and "b" components of `inverse_memory_index`
+            // by preserving the order but keeping only one disjoint "half" each.
+            // FIXME(eddyb) build a better abstraction for permutations, if possible.
+            let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index
+                .iter()
+                .filter_map(|&i| i.index().checked_sub(b_start.index()).map(FieldIdx::new))
+                .collect();
+            inverse_memory_index.raw.retain(|&i| i.index() < b_start.index());
+            let inverse_memory_index_a = inverse_memory_index;
+
+            // Since `inverse_memory_index_{a,b}` each only refer to their
+            // respective fields, they can be safely inverted
+            let memory_index_a = inverse_memory_index_a.invert_bijective_mapping();
+            let memory_index_b = inverse_memory_index_b.invert_bijective_mapping();
+
+            let outer_fields =
+                FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
+            (outer_fields, offsets_b, memory_index_b)
+        }
+        _ => unreachable!(),
+    };
+
+    let mut size = prefix.size;
+    let mut align = prefix.align;
+    let variants = variant_fields
+        .iter_enumerated()
+        .map(|(index, variant_fields)| {
+            // Only include overlap-eligible fields when we compute our variant layout.
+            let variant_only_tys = variant_fields
+                .iter()
+                .filter(|local| match assignments[**local] {
+                    Unassigned => unreachable!(),
+                    Assigned(v) if v == index => true,
+                    Assigned(_) => unreachable!("assignment does not match variant"),
+                    Ineligible(_) => false,
+                })
+                .map(|local| local_layouts[*local]);
+
+            let mut variant = calc.univariant(
+                &variant_only_tys.collect::<IndexVec<_, _>>(),
+                &ReprOptions::default(),
+                StructKind::Prefixed(prefix_size, prefix_align.abi),
+            )?;
+            variant.variants = Variants::Single { index };
+
+            let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
+                unreachable!();
+            };
+
+            // Now, stitch the promoted and variant-only fields back together in
+            // the order they are mentioned by our CoroutineLayout.
+            // Because we only use some subset (that can differ between variants)
+            // of the promoted fields, we can't just pick those elements of the
+            // `promoted_memory_index` (as we'd end up with gaps).
+            // So instead, we build an "inverse memory_index", as if all of the
+            // promoted fields were being used, but leave the elements not in the
+            // subset as `invalid_field_idx`, which we can filter out later to
+            // obtain a valid (bijective) mapping.
+            let invalid_field_idx = promoted_memory_index.len() + memory_index.len();
+            let mut combined_inverse_memory_index =
+                IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx);
+
+            let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
+            let combined_offsets = variant_fields
+                .iter_enumerated()
+                .map(|(i, local)| {
+                    let (offset, memory_index) = match assignments[*local] {
+                        Unassigned => unreachable!(),
+                        Assigned(_) => {
+                            let (offset, memory_index) = offsets_and_memory_index.next().unwrap();
+                            (offset, promoted_memory_index.len() as u32 + memory_index)
+                        }
+                        Ineligible(field_idx) => {
+                            let field_idx = field_idx.unwrap();
+                            (promoted_offsets[field_idx], promoted_memory_index[field_idx])
+                        }
+                    };
+                    combined_inverse_memory_index[memory_index] = i;
+                    offset
+                })
+                .collect();
+
+            // Remove the unused slots and invert the mapping to obtain the
+            // combined `memory_index` (also see previous comment).
+            combined_inverse_memory_index.raw.retain(|&i| i.index() != invalid_field_idx);
+            let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping();
+
+            variant.fields = FieldsShape::Arbitrary {
+                offsets: combined_offsets,
+                memory_index: combined_memory_index,
+            };
+
+            size = size.max(variant.size);
+            align = align.max(variant.align);
+            Ok(variant)
+        })
+        .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+    size = size.align_to(align.abi);
+
+    let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited());
+    let abi = BackendRepr::Memory { sized: true };
+
+    Ok(LayoutData {
+        variants: Variants::Multiple {
+            tag,
+            tag_encoding: TagEncoding::Direct,
+            tag_field: tag_index,
+            variants,
+        },
+        fields: outer_fields,
+        backend_repr: abi,
+        // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to
+        // self-referentiality), getting the discriminant can cause aliasing violations.
+        // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that
+        // would do the same for us here.
+        // See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>.
+        // FIXME: Remove when <https://github.com/rust-lang/rust/issues/125735> is implemented and aliased coroutine fields are wrapped in `UnsafePinned`.
+        largest_niche: None,
+        uninhabited,
+        size,
+        align,
+        max_repr_align: None,
+        unadjusted_abi_align: align.abi,
+        randomization_seed: Default::default(),
+    })
+}
diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs
new file mode 100644
index 00000000000..0d0706defc2
--- /dev/null
+++ b/compiler/rustc_abi/src/layout/simple.rs
@@ -0,0 +1,148 @@
+use std::num::NonZero;
+
+use rustc_hashes::Hash64;
+use rustc_index::{Idx, IndexVec};
+
+use crate::{
+    BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants,
+};
+
+/// "Simple" layout constructors that cannot fail.
+impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
+    pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self {
+        let dl = cx.data_layout();
+        LayoutData {
+            variants: Variants::Single { index: VariantIdx::new(0) },
+            fields: FieldsShape::Arbitrary {
+                offsets: IndexVec::new(),
+                memory_index: IndexVec::new(),
+            },
+            backend_repr: BackendRepr::Memory { sized },
+            largest_niche: None,
+            uninhabited: false,
+            align: dl.i8_align,
+            size: Size::ZERO,
+            max_repr_align: None,
+            unadjusted_abi_align: dl.i8_align.abi,
+            randomization_seed: Hash64::new(0),
+        }
+    }
+
+    pub fn never_type<C: HasDataLayout>(cx: &C) -> Self {
+        let dl = cx.data_layout();
+        // This is also used for uninhabited enums, so we use `Variants::Empty`.
+        LayoutData {
+            variants: Variants::Empty,
+            fields: FieldsShape::Primitive,
+            backend_repr: BackendRepr::Memory { sized: true },
+            largest_niche: None,
+            uninhabited: true,
+            align: dl.i8_align,
+            size: Size::ZERO,
+            max_repr_align: None,
+            unadjusted_abi_align: dl.i8_align.abi,
+            randomization_seed: Hash64::ZERO,
+        }
+    }
+
+    pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
+        let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
+        let size = scalar.size(cx);
+        let align = scalar.align(cx);
+
+        let range = scalar.valid_range(cx);
+
+        // All primitive types for which we don't have subtype coercions should get a distinct seed,
+        // so that types wrapping them can use randomization to arrive at distinct layouts.
+        //
+        // Some type information is already lost at this point, so as an approximation we derive
+        // the seed from what remains. For example on 64-bit targets usize and u64 can no longer
+        // be distinguished.
+        let randomization_seed = size
+            .bytes()
+            .wrapping_add(
+                match scalar.primitive() {
+                    Primitive::Int(_, true) => 1,
+                    Primitive::Int(_, false) => 2,
+                    Primitive::Float(_) => 3,
+                    Primitive::Pointer(_) => 4,
+                } << 32,
+            )
+            // distinguishes references from pointers
+            .wrapping_add((range.start as u64).rotate_right(16))
+            // distinguishes char from u32 and bool from u8
+            .wrapping_add((range.end as u64).rotate_right(16));
+
+        LayoutData {
+            variants: Variants::Single { index: VariantIdx::new(0) },
+            fields: FieldsShape::Primitive,
+            backend_repr: BackendRepr::Scalar(scalar),
+            largest_niche,
+            uninhabited: false,
+            size,
+            align,
+            max_repr_align: None,
+            unadjusted_abi_align: align.abi,
+            randomization_seed: Hash64::new(randomization_seed),
+        }
+    }
+
+    pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self {
+        let dl = cx.data_layout();
+        let b_align = b.align(dl);
+        let align = a.align(dl).max(b_align).max(dl.aggregate_align);
+        let b_offset = a.size(dl).align_to(b_align.abi);
+        let size = (b_offset + b.size(dl)).align_to(align.abi);
+
+        // HACK(nox): We iter on `b` and then `a` because `max_by_key`
+        // returns the last maximum.
+        let largest_niche = Niche::from_scalar(dl, b_offset, b)
+            .into_iter()
+            .chain(Niche::from_scalar(dl, Size::ZERO, a))
+            .max_by_key(|niche| niche.available(dl));
+
+        let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes());
+
+        LayoutData {
+            variants: Variants::Single { index: VariantIdx::new(0) },
+            fields: FieldsShape::Arbitrary {
+                offsets: [Size::ZERO, b_offset].into(),
+                memory_index: [0, 1].into(),
+            },
+            backend_repr: BackendRepr::ScalarPair(a, b),
+            largest_niche,
+            uninhabited: false,
+            align,
+            size,
+            max_repr_align: None,
+            unadjusted_abi_align: align.abi,
+            randomization_seed: Hash64::new(combined_seed),
+        }
+    }
+
+    /// Returns a dummy layout for an uninhabited variant.
+    ///
+    /// Uninhabited variants get pruned as part of the layout calculation,
+    /// so this can be used after the fact to reconstitute a layout.
+    pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
+        let dl = cx.data_layout();
+        LayoutData {
+            variants: Variants::Single { index },
+            fields: match NonZero::new(fields) {
+                Some(fields) => FieldsShape::Union(fields),
+                None => FieldsShape::Arbitrary {
+                    offsets: IndexVec::new(),
+                    memory_index: IndexVec::new(),
+                },
+            },
+            backend_repr: BackendRepr::Memory { sized: true },
+            largest_niche: None,
+            uninhabited: true,
+            align: dl.i8_align,
+            size: Size::ZERO,
+            max_repr_align: None,
+            unadjusted_abi_align: dl.i8_align.abi,
+            randomization_seed: Hash64::ZERO,
+        }
+    }
+}
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index 03f3f043c21..4f43c0e6f8e 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -150,6 +150,12 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
     }
 }
 
+impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
+    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
+        &*self.layout.0.0
+    }
+}
+
 /// Trait that needs to be implemented by the higher-level type representation
 /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
 pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index a59dc870aa3..1b737582009 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -205,6 +205,13 @@ impl ReprOptions {
     }
 }
 
+/// The maximum supported number of lanes in a SIMD vector.
+///
+/// This value is selected based on backend support:
+/// * LLVM does not appear to have a vector width limit.
+/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
+pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
+
 /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
 /// for a target, which contains everything needed to compute layouts.
 #[derive(Debug, PartialEq, Eq)]
@@ -1744,48 +1751,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
     pub fn is_uninhabited(&self) -> bool {
         self.uninhabited
     }
-
-    pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
-        let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
-        let size = scalar.size(cx);
-        let align = scalar.align(cx);
-
-        let range = scalar.valid_range(cx);
-
-        // All primitive types for which we don't have subtype coercions should get a distinct seed,
-        // so that types wrapping them can use randomization to arrive at distinct layouts.
-        //
-        // Some type information is already lost at this point, so as an approximation we derive
-        // the seed from what remains. For example on 64-bit targets usize and u64 can no longer
-        // be distinguished.
-        let randomization_seed = size
-            .bytes()
-            .wrapping_add(
-                match scalar.primitive() {
-                    Primitive::Int(_, true) => 1,
-                    Primitive::Int(_, false) => 2,
-                    Primitive::Float(_) => 3,
-                    Primitive::Pointer(_) => 4,
-                } << 32,
-            )
-            // distinguishes references from pointers
-            .wrapping_add((range.start as u64).rotate_right(16))
-            // distinguishes char from u32 and bool from u8
-            .wrapping_add((range.end as u64).rotate_right(16));
-
-        LayoutData {
-            variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldsShape::Primitive,
-            backend_repr: BackendRepr::Scalar(scalar),
-            largest_niche,
-            uninhabited: false,
-            size,
-            align,
-            max_repr_align: None,
-            unadjusted_abi_align: align.abi,
-            randomization_seed: Hash64::new(randomization_seed),
-        }
-    }
 }
 
 impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index b21ccba93bb..3b44e996358 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -93,7 +93,7 @@ impl<T> ArenaChunk<T> {
     #[inline]
     fn end(&mut self) -> *mut T {
         unsafe {
-            if mem::size_of::<T>() == 0 {
+            if size_of::<T>() == 0 {
                 // A pointer as large as possible for zero-sized elements.
                 ptr::without_provenance_mut(!0)
             } else {
@@ -151,7 +151,7 @@ impl<T> TypedArena<T> {
         }
 
         unsafe {
-            if mem::size_of::<T>() == 0 {
+            if size_of::<T>() == 0 {
                 self.ptr.set(self.ptr.get().wrapping_byte_add(1));
                 let ptr = ptr::NonNull::<T>::dangling().as_ptr();
                 // Don't drop the object. This `write` is equivalent to `forget`.
@@ -173,13 +173,13 @@ impl<T> TypedArena<T> {
         // FIXME: this should *likely* use `offset_from`, but more
         // investigation is needed (including running tests in miri).
         let available_bytes = self.end.get().addr() - self.ptr.get().addr();
-        let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap();
+        let additional_bytes = additional.checked_mul(size_of::<T>()).unwrap();
         available_bytes >= additional_bytes
     }
 
     #[inline]
     fn alloc_raw_slice(&self, len: usize) -> *mut T {
-        assert!(mem::size_of::<T>() != 0);
+        assert!(size_of::<T>() != 0);
         assert!(len != 0);
 
         // Ensure the current chunk can fit `len` objects.
@@ -213,7 +213,7 @@ impl<T> TypedArena<T> {
         // So we collect all the elements beforehand, which takes care of reentrancy and panic
         // safety. This function is much less hot than `DroplessArena::alloc_from_iter`, so it
         // doesn't need to be hyper-optimized.
-        assert!(mem::size_of::<T>() != 0);
+        assert!(size_of::<T>() != 0);
 
         let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
         if vec.is_empty() {
@@ -236,7 +236,7 @@ impl<T> TypedArena<T> {
         unsafe {
             // We need the element size to convert chunk sizes (ranging from
             // PAGE to HUGE_PAGE bytes) to element counts.
-            let elem_size = cmp::max(1, mem::size_of::<T>());
+            let elem_size = cmp::max(1, size_of::<T>());
             let mut chunks = self.chunks.borrow_mut();
             let mut new_cap;
             if let Some(last_chunk) = chunks.last_mut() {
@@ -246,7 +246,7 @@ impl<T> TypedArena<T> {
                     // FIXME: this should *likely* use `offset_from`, but more
                     // investigation is needed (including running tests in miri).
                     let used_bytes = self.ptr.get().addr() - last_chunk.start().addr();
-                    last_chunk.entries = used_bytes / mem::size_of::<T>();
+                    last_chunk.entries = used_bytes / size_of::<T>();
                 }
 
                 // If the previous chunk's len is less than HUGE_PAGE
@@ -276,7 +276,7 @@ impl<T> TypedArena<T> {
         let end = self.ptr.get().addr();
         // We then calculate the number of elements to be dropped in the last chunk,
         // which is the filled area's length.
-        let diff = if mem::size_of::<T>() == 0 {
+        let diff = if size_of::<T>() == 0 {
             // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
             // the number of zero-sized values in the last and only chunk, just out of caution.
             // Recall that `end` was incremented for each allocated value.
@@ -284,7 +284,7 @@ impl<T> TypedArena<T> {
         } else {
             // FIXME: this should *likely* use `offset_from`, but more
             // investigation is needed (including running tests in miri).
-            (end - start) / mem::size_of::<T>()
+            (end - start) / size_of::<T>()
         };
         // Pass that to the `destroy` method.
         unsafe {
@@ -329,7 +329,7 @@ fn align_up(val: usize, align: usize) -> usize {
 
 // Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them
 // to optimize away alignment code.
-const DROPLESS_ALIGNMENT: usize = mem::align_of::<usize>();
+const DROPLESS_ALIGNMENT: usize = align_of::<usize>();
 
 /// An arena that can hold objects of multiple different types that impl `Copy`
 /// and/or satisfy `!mem::needs_drop`.
@@ -447,7 +447,7 @@ impl DroplessArena {
     #[inline]
     pub fn alloc<T>(&self, object: T) -> &mut T {
         assert!(!mem::needs_drop::<T>());
-        assert!(mem::size_of::<T>() != 0);
+        assert!(size_of::<T>() != 0);
 
         let mem = self.alloc_raw(Layout::new::<T>()) as *mut T;
 
@@ -471,7 +471,7 @@ impl DroplessArena {
         T: Copy,
     {
         assert!(!mem::needs_drop::<T>());
-        assert!(mem::size_of::<T>() != 0);
+        assert!(size_of::<T>() != 0);
         assert!(!slice.is_empty());
 
         let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T;
@@ -546,7 +546,7 @@ impl DroplessArena {
         // Warning: this function is reentrant: `iter` could hold a reference to `&self` and
         // allocate additional elements while we're iterating.
         let iter = iter.into_iter();
-        assert!(mem::size_of::<T>() != 0);
+        assert!(size_of::<T>() != 0);
         assert!(!mem::needs_drop::<T>());
 
         let size_hint = iter.size_hint();
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 11fc409cf43..002435b2d03 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1399,6 +1399,7 @@ impl Expr {
             // Never need parens
             ExprKind::Array(_)
             | ExprKind::Await(..)
+            | ExprKind::Use(..)
             | ExprKind::Block(..)
             | ExprKind::Call(..)
             | ExprKind::ConstBlock(_)
@@ -1588,6 +1589,8 @@ pub enum ExprKind {
     Gen(CaptureBy, P<Block>, GenBlockKind, Span),
     /// An await expression (`my_future.await`). Span is of await keyword.
     Await(P<Expr>, Span),
+    /// A use expression (`x.use`). Span is of use keyword.
+    Use(P<Expr>, Span),
 
     /// A try block (`try { ... }`).
     TryBlock(P<Block>),
@@ -1757,8 +1760,17 @@ pub enum CaptureBy {
         /// The span of the `move` keyword.
         move_kw: Span,
     },
-    /// `move` keyword was not specified.
+    /// `move` or `use` keywords were not specified.
     Ref,
+    /// `use |x| y + x`.
+    ///
+    /// Note that if you have a regular closure like `|| x.use`, this will *not* result
+    /// in a `Use` capture. Instead, the `ExprUseVisitor` will look at the type
+    /// of `x` and treat `x.use` as either a copy/clone/move as appropriate.
+    Use {
+        /// The span of the `use` keyword.
+        use_kw: Span,
+    },
 }
 
 /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 8a64ce4654d..37abd20133c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1733,6 +1733,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
             vis.visit_expr(expr);
             vis.visit_span(await_kw_span);
         }
+        ExprKind::Use(expr, use_kw_span) => {
+            vis.visit_expr(expr);
+            vis.visit_span(use_kw_span);
+        }
         ExprKind::Assign(el, er, span) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
@@ -1883,6 +1887,9 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
         CaptureBy::Value { move_kw } => {
             vis.visit_span(move_kw);
         }
+        CaptureBy::Use { use_kw } => {
+            vis.visit_span(use_kw);
+        }
     }
 }
 
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 64f2a98b8a6..e43d78f6e72 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
             Assign(e, _, _)
             | AssignOp(_, e, _)
             | Await(e, _)
+            | Use(e, _)
             | Binary(_, e, _)
             | Call(e, _)
             | Cast(e, _)
@@ -224,6 +225,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
             | Lit(_)
             | Type(_, _)
             | Await(_, _)
+            | Use(_, _)
             | Field(_, _)
             | Index(_, _, _)
             | Underscore
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 37139e664f3..43ffbe9b071 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1211,6 +1211,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
         }
         ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)),
         ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)),
+        ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)),
         ExprKind::Assign(lhs, rhs, _span) => {
             try_visit!(visitor.visit_expr(lhs));
             try_visit!(visitor.visit_expr(rhs));
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index d8b7cb0c322..571172be4ed 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -60,25 +60,27 @@ pub(crate) struct DelegationResults<'hir> {
 }
 
 impl<'hir> LoweringContext<'_, 'hir> {
-    pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
+    /// Defines whether the delegatee is an associated function whose first parameter is `self`.
+    pub(crate) fn delegatee_is_method(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
         let sig_id = self.get_delegation_sig_id(item_id, path_id, span);
         let Ok(sig_id) = sig_id else {
             return false;
         };
-        self.has_self(sig_id, span)
+        self.is_method(sig_id, span)
     }
 
-    fn has_self(&self, def_id: DefId, span: Span) -> bool {
-        if let Some(local_sig_id) = def_id.as_local() {
-            // The value may be missing due to recursive delegation.
-            // Error will be emitted later during HIR ty lowering.
-            self.resolver.delegation_fn_sigs.get(&local_sig_id).is_some_and(|sig| sig.has_self)
-        } else {
-            match self.tcx.def_kind(def_id) {
-                DefKind::Fn => false,
-                DefKind::AssocFn => self.tcx.associated_item(def_id).fn_has_self_parameter,
-                _ => span_bug!(span, "unexpected DefKind for delegation item"),
-            }
+    fn is_method(&self, def_id: DefId, span: Span) -> bool {
+        match self.tcx.def_kind(def_id) {
+            DefKind::Fn => false,
+            DefKind::AssocFn => match def_id.as_local() {
+                Some(local_def_id) => self
+                    .resolver
+                    .delegation_fn_sigs
+                    .get(&local_def_id)
+                    .is_some_and(|sig| sig.has_self),
+                None => self.tcx.associated_item(def_id).fn_has_self_parameter,
+            },
+            _ => span_bug!(span, "unexpected DefKind for delegation item"),
         }
     }
 
@@ -324,7 +326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let call = if self
             .get_resolution_id(delegation.id, span)
-            .and_then(|def_id| Ok(self.has_self(def_id, span)))
+            .and_then(|def_id| Ok(self.is_method(def_id, span)))
             .unwrap_or_default()
             && delegation.qself.is_none()
             && !has_generic_args
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 9c3db7abc1c..acf35b75e4d 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -13,7 +13,7 @@ use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{Spanned, respan};
-use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
 use thin_vec::{ThinVec, thin_vec};
 use visit::{Visitor, walk_expr};
 
@@ -207,6 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     },
                 ),
                 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
+                ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),
                 ExprKind::Closure(box Closure {
                     binder,
                     capture_clause,
@@ -483,7 +484,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             if legacy_args_idx.contains(&idx) {
                 let parent_def_id = self.current_hir_id_owner.def_id;
                 let node_id = self.next_node_id();
-                self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
+                self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span);
                 let mut visitor = WillCreateDefIdsVisitor {};
                 let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
                     AstP(Expr {
@@ -1067,6 +1068,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         )
     }
 
+    fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+        hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
+    }
+
     fn lower_expr_closure(
         &mut self,
         binder: &ClosureBinder,
@@ -1690,6 +1695,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let yielded =
             opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
 
+        if !self.tcx.features().yield_expr()
+            && !self.tcx.features().coroutines()
+            && !self.tcx.features().gen_blocks()
+        {
+            rustc_session::parse::feature_err(
+                &self.tcx.sess,
+                sym::yield_expr,
+                span,
+                fluent_generated::ast_lowering_yield,
+            )
+            .emit();
+        }
+
         let is_async_gen = match self.coroutine_kind {
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
@@ -1714,28 +1732,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     None,
                 );
             }
-            Some(hir::CoroutineKind::Coroutine(_)) => {
-                if !self.tcx.features().coroutines() {
-                    rustc_session::parse::feature_err(
-                        &self.tcx.sess,
-                        sym::coroutines,
-                        span,
-                        fluent_generated::ast_lowering_yield,
-                    )
-                    .emit();
-                }
-                false
-            }
+            Some(hir::CoroutineKind::Coroutine(_)) => false,
             None => {
-                if !self.tcx.features().coroutines() {
-                    rustc_session::parse::feature_err(
-                        &self.tcx.sess,
-                        sym::coroutines,
-                        span,
-                        fluent_generated::ast_lowering_yield,
-                    )
-                    .emit();
-                }
                 let suggestion = self.current_item.map(|s| s.shrink_to_lo());
                 self.dcx().emit_err(YieldInClosure { span, suggestion });
                 self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 5e89321e6ec..b01ca54fb6f 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -871,7 +871,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
             }
             AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
-                has_self: self.delegation_has_self(i.id, delegation.id, i.span),
+                has_self: self.delegatee_is_method(i.id, delegation.id, i.span),
             },
             AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
                 panic!("macros should have been expanded by now")
@@ -1000,7 +1000,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
                 }
                 AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
-                    has_self: self.delegation_has_self(i.id, delegation.id, i.span),
+                    has_self: self.delegatee_is_method(i.id, delegation.id, i.span),
                 },
                 AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
                     panic!("macros should have been expanded by now")
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 7cdc3afaca7..d65303e1ea4 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -495,7 +495,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         parent: LocalDefId,
         node_id: ast::NodeId,
-        name: Symbol,
+        name: Option<Symbol>,
         def_kind: DefKind,
         span: Span,
     ) -> LocalDefId {
@@ -775,7 +775,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let _def_id = self.create_def(
                     self.current_hir_id_owner.def_id,
                     param,
-                    kw::UnderscoreLifetime,
+                    Some(kw::UnderscoreLifetime),
                     DefKind::LifetimeParam,
                     ident.span,
                 );
@@ -2090,8 +2090,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // We're lowering a const argument that was originally thought to be a type argument,
             // so the def collector didn't create the def ahead of time. That's why we have to do
             // it here.
-            let def_id =
-                self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
+            let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span);
             let hir_id = self.lower_node_id(node_id);
 
             let path_expr = Expr {
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 728981dea5f..07cc64a1358 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::span_bug;
 use rustc_span::source_map::{Spanned, respan};
-use rustc_span::{DesugaringKind, Ident, Span, kw};
+use rustc_span::{DesugaringKind, Ident, Span};
 
 use super::errors::{
     ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
@@ -523,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // We're generating a range end that didn't exist in the AST,
         // so the def collector didn't create the def ahead of time. That's why we have to do
         // it here.
-        let def_id = self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
+        let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span);
         let hir_id = self.lower_node_id(node_id);
 
         let unstable_span = self.mark_span_with_reason(
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index de11fe770c5..31ff102c127 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -489,6 +489,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(dyn_star, "`dyn*` trait objects are experimental");
     gate_all!(const_closures, "const closures are experimental");
     gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
+    gate_all!(ergonomic_clones, "ergonomic clones are experimental");
     gate_all!(explicit_tail_calls, "`become` expression is experimental");
     gate_all!(generic_const_items, "generic const items are experimental");
     gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 496323a35b8..e3c41f117ab 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -574,6 +574,14 @@ impl<'a> State<'a> {
                 );
                 self.word(".await");
             }
+            ast::ExprKind::Use(expr, _) => {
+                self.print_expr_cond_paren(
+                    expr,
+                    expr.precedence() < ExprPrecedence::Unambiguous,
+                    fixup,
+                );
+                self.word(".use");
+            }
             ast::ExprKind::Assign(lhs, rhs, _) => {
                 self.print_expr_cond_paren(
                     lhs,
@@ -885,6 +893,7 @@ impl<'a> State<'a> {
     fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
         match capture_clause {
             ast::CaptureBy::Value { .. } => self.word_space("move"),
+            ast::CaptureBy::Use { .. } => self.word_space("use"),
             ast::CaptureBy::Ref => {}
         }
     }
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index e4bb459e6df..f4986d1d187 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -149,3 +149,47 @@ print_tup!(A B C D E F G H);
 print_skip!(Span, ());
 print_disp!(Symbol, u16, bool, NonZero<u32>);
 print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
+
+/// Finds attributes in sequences of attributes by pattern matching.
+///
+/// A little like `matches` but for attributes.
+///
+/// ```rust,ignore (illustrative)
+/// // finds the repr attribute
+/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
+///
+/// }
+///
+/// // checks if one has matched
+/// if find_attr!(attrs, AttributeKind::Repr(_)) {
+///
+/// }
+/// ```
+///
+/// Often this requires you to first end up with a list of attributes.
+/// A common way to get those is through `tcx.get_all_attrs(did)`
+#[macro_export]
+macro_rules! find_attr {
+    ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{
+        $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some()
+    }};
+
+    ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
+        fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {}
+        check_attribute_iterator(&$attributes_list);
+
+        let find_attribute = |iter| {
+            for i in $attributes_list {
+                match i {
+                    rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
+                        return Some($e);
+                    }
+                    _ => {}
+                }
+            }
+
+            None
+        };
+        find_attribute($attributes_list)
+    }};
+}
diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml
index c335eeb5f71..6b4ce957630 100644
--- a/compiler/rustc_attr_parsing/Cargo.toml
+++ b/compiler/rustc_attr_parsing/Cargo.toml
@@ -16,6 +16,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_middle = { path = "../rustc_middle" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index ee43f1b82aa..e665d4e0a49 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -96,47 +96,3 @@ pub use context::{AttributeParser, OmitDoc};
 pub use rustc_attr_data_structures::*;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
-
-/// Finds attributes in sequences of attributes by pattern matching.
-///
-/// A little like `matches` but for attributes.
-///
-/// ```rust,ignore (illustrative)
-/// // finds the repr attribute
-/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
-///
-/// }
-///
-/// // checks if one has matched
-/// if find_attr!(attrs, AttributeKind::Repr(_)) {
-///
-/// }
-/// ```
-///
-/// Often this requires you to first end up with a list of attributes.
-/// A common way to get those is through `tcx.get_all_attrs(did)`
-#[macro_export]
-macro_rules! find_attr {
-    ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{
-        $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some()
-    }};
-
-    ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
-        fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {}
-        check_attribute_iterator(&$attributes_list);
-
-        let find_attribute = |iter| {
-            for i in $attributes_list {
-                match i {
-                    rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
-                        return Some($e);
-                    }
-                    _ => {}
-                }
-            }
-
-            None
-        };
-        find_attribute($attributes_list)
-    }};
-}
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 30e94b0bec7..c9be5575da5 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 .expect_closure();
             let span = match capture_clause {
                 rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(),
+                rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(),
                 rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
             };
             diag.span_suggestion_verbose(
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 9d500586f08..1209d8bf596 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -1,11 +1,8 @@
 use rustc_data_structures::graph;
 use rustc_index::IndexVec;
-use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
-use rustc_span::DUMMY_SP;
+use rustc_middle::ty::RegionVid;
 
 use crate::constraints::{OutlivesConstraint, OutlivesConstraintIndex, OutlivesConstraintSet};
-use crate::type_check::Locations;
 
 /// The construct graph organizes the constraints by their end-points.
 /// It can be used to view a `R1: R2` constraint as either an edge `R1
@@ -23,8 +20,8 @@ pub(crate) type ReverseConstraintGraph = ConstraintGraph<Reverse>;
 /// Marker trait that controls whether a `R1: R2` constraint
 /// represents an edge `R1 -> R2` or `R2 -> R1`.
 pub(crate) trait ConstraintGraphDirection: Copy + 'static {
-    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
-    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
+    fn start_region(sup: RegionVid, sub: RegionVid) -> RegionVid;
+    fn end_region(sup: RegionVid, sub: RegionVid) -> RegionVid;
     fn is_normal() -> bool;
 }
 
@@ -36,12 +33,12 @@ pub(crate) trait ConstraintGraphDirection: Copy + 'static {
 pub(crate) struct Normal;
 
 impl ConstraintGraphDirection for Normal {
-    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
-        c.sup
+    fn start_region(sup: RegionVid, _sub: RegionVid) -> RegionVid {
+        sup
     }
 
-    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
-        c.sub
+    fn end_region(_sup: RegionVid, sub: RegionVid) -> RegionVid {
+        sub
     }
 
     fn is_normal() -> bool {
@@ -57,12 +54,12 @@ impl ConstraintGraphDirection for Normal {
 pub(crate) struct Reverse;
 
 impl ConstraintGraphDirection for Reverse {
-    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
-        c.sub
+    fn start_region(_sup: RegionVid, sub: RegionVid) -> RegionVid {
+        sub
     }
 
-    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
-        c.sup
+    fn end_region(sup: RegionVid, _sub: RegionVid) -> RegionVid {
+        sup
     }
 
     fn is_normal() -> bool {
@@ -84,7 +81,7 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> {
         let mut next_constraints = IndexVec::from_elem(None, &set.outlives);
 
         for (idx, constraint) in set.outlives.iter_enumerated().rev() {
-            let head = &mut first_constraints[D::start_region(constraint)];
+            let head = &mut first_constraints[D::start_region(constraint.sup, constraint.sub)];
             let next = &mut next_constraints[idx];
             debug_assert!(next.is_none());
             *next = *head;
@@ -105,63 +102,57 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> {
         RegionGraph::new(set, self, static_region)
     }
 
+    pub(crate) fn is_normal(&self) -> bool {
+        D::is_normal()
+    }
+
     /// Given a region `R`, iterate over all constraints `R: R1`.
-    pub(crate) fn outgoing_edges<'a, 'tcx>(
+    pub(crate) fn outgoing_edges_from_graph<'a, 'tcx>(
         &'a self,
         region_sup: RegionVid,
         constraints: &'a OutlivesConstraintSet<'tcx>,
-        static_region: RegionVid,
-    ) -> Edges<'a, 'tcx, D> {
-        //if this is the `'static` region and the graph's direction is normal,
-        //then setup the Edges iterator to return all regions #53178
-        if region_sup == static_region && D::is_normal() {
-            Edges {
-                graph: self,
-                constraints,
-                pointer: None,
-                next_static_idx: Some(0),
-                static_region,
-            }
-        } else {
-            //otherwise, just setup the iterator as normal
-            let first = self.first_constraints[region_sup];
-            Edges { graph: self, constraints, pointer: first, next_static_idx: None, static_region }
-        }
+    ) -> EdgesFromGraph<'a, 'tcx, D> {
+        EdgesFromGraph { graph: self, constraints, pointer: self.first_constraints[region_sup] }
+    }
+
+    /// Returns all regions (#53178).
+    pub(crate) fn outgoing_edges_from_static(&self) -> EdgesFromStatic {
+        EdgesFromStatic { next_static_idx: 0, end_static_idx: self.first_constraints.len() }
     }
 }
 
-pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> {
+pub(crate) struct EdgesFromGraph<'a, 'tcx, D: ConstraintGraphDirection> {
     graph: &'a ConstraintGraph<D>,
     constraints: &'a OutlivesConstraintSet<'tcx>,
     pointer: Option<OutlivesConstraintIndex>,
-    next_static_idx: Option<usize>,
-    static_region: RegionVid,
 }
 
-impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> {
-    type Item = OutlivesConstraint<'tcx>;
+impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for EdgesFromGraph<'a, 'tcx, D> {
+    type Item = &'a OutlivesConstraint<'tcx>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(p) = self.pointer {
             self.pointer = self.graph.next_constraints[p];
+            Some(&self.constraints[p])
+        } else {
+            None
+        }
+    }
+}
+
+pub(crate) struct EdgesFromStatic {
+    next_static_idx: usize,
+    end_static_idx: usize,
+}
+
+impl Iterator for EdgesFromStatic {
+    type Item = RegionVid;
 
-            Some(self.constraints[p])
-        } else if let Some(next_static_idx) = self.next_static_idx {
-            self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
-                None
-            } else {
-                Some(next_static_idx + 1)
-            };
-
-            Some(OutlivesConstraint {
-                sup: self.static_region,
-                sub: next_static_idx.into(),
-                locations: Locations::All(DUMMY_SP),
-                span: DUMMY_SP,
-                category: ConstraintCategory::Internal,
-                variance_info: VarianceDiagInfo::default(),
-                from_closure: false,
-            })
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next_static_idx < self.end_static_idx {
+            let ret = RegionVid::from_usize(self.next_static_idx);
+            self.next_static_idx += 1;
+            Some(ret)
         } else {
             None
         }
@@ -193,21 +184,38 @@ impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> {
     /// Given a region `R`, iterate over all regions `R1` such that
     /// there exists a constraint `R: R1`.
     pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> {
-        Successors {
-            edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
+        // If this is the `'static` region and the graph's direction is normal,
+        // then setup the Edges iterator to return all regions (#53178).
+        if region_sup == self.static_region && D::is_normal() {
+            Successors::FromStatic(self.constraint_graph.outgoing_edges_from_static())
+        } else {
+            // Otherwise, just setup the iterator as normal.
+            Successors::FromGraph(
+                self.constraint_graph.outgoing_edges_from_graph(region_sup, self.set),
+            )
         }
     }
 }
 
-pub(crate) struct Successors<'a, 'tcx, D: ConstraintGraphDirection> {
-    edges: Edges<'a, 'tcx, D>,
+pub(crate) enum Successors<'a, 'tcx, D: ConstraintGraphDirection> {
+    FromStatic(EdgesFromStatic),
+    FromGraph(EdgesFromGraph<'a, 'tcx, D>),
 }
 
 impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'a, 'tcx, D> {
     type Item = RegionVid;
 
     fn next(&mut self) -> Option<Self::Item> {
-        self.edges.next().map(|c| D::end_region(&c))
+        match self {
+            Successors::FromStatic(edges) => {
+                // No `D::end_region` call needed here: static successors are only possible when
+                // the direction is `Normal`, so we can directly use what would be the `sub` value.
+                edges.next()
+            }
+            Successors::FromGraph(edges) => {
+                edges.next().map(|constraint| D::end_region(constraint.sup, constraint.sub))
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index be4a7736b1c..145137f9236 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                             ) => {
                                 capture_reason = format!("mutable borrow of `{upvar}`");
                             }
-                            ty::UpvarCapture::ByValue => {
+                            ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
                                 capture_reason = format!("possible mutation of `{upvar}`");
                             }
                             _ => bug!("upvar `{upvar}` borrowed, but not mutably"),
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index b42f45dc76c..5454b26ffb4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1491,14 +1491,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                         let stmt = &bbd.statements[loc.statement_index];
                         debug!("temporary assigned in: stmt={:?}", stmt);
 
-                        if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind
-                        {
-                            propagate_closure_used_mut_place(self, source);
-                        } else {
-                            bug!(
-                                "closures should only capture user variables \
+                        match stmt.kind {
+                            StatementKind::Assign(box (
+                                _,
+                                Rvalue::Ref(_, _, source)
+                                | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
+                            )) => {
+                                propagate_closure_used_mut_place(self, source);
+                            }
+                            _ => {
+                                bug!(
+                                    "closures should only capture user variables \
                                  or references to user variables"
-                            );
+                                );
+                            }
                         }
                     }
                     _ => propagate_closure_used_mut_place(self, place),
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index a00fce08c9b..bb209a95711 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -21,8 +21,8 @@ use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::fold::fold_regions;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
 use rustc_mir_dataflow::points::DenseLocationMap;
-use rustc_span::Span;
 use rustc_span::hygiene::DesugaringKind;
+use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument, trace};
 
 use crate::BorrowckInferCtxt;
@@ -311,9 +311,11 @@ enum RegionRelationCheckResult {
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
-enum Trace<'tcx> {
+enum Trace<'a, 'tcx> {
     StartRegion,
-    FromOutlivesConstraint(OutlivesConstraint<'tcx>),
+    FromGraph(&'a OutlivesConstraint<'tcx>),
+    FromStatic(RegionVid),
+    FromMember(RegionVid, RegionVid, Span),
     NotVisited,
 }
 
@@ -1764,6 +1766,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
         context[from_region] = Trace::StartRegion;
 
+        let fr_static = self.universal_regions().fr_static;
+
         // Use a deque so that we do a breadth-first search. We will
         // stop at the first match, which ought to be the shortest
         // path (fewest constraints).
@@ -1783,13 +1787,39 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             if target_test(r) {
                 let mut result = vec![];
                 let mut p = r;
+                // This loop is cold and runs at the end, which is why we delay
+                // `OutlivesConstraint` construction until now.
                 loop {
-                    match context[p].clone() {
-                        Trace::NotVisited => {
-                            bug!("found unvisited region {:?} on path to {:?}", p, r)
+                    match context[p] {
+                        Trace::FromGraph(c) => {
+                            p = c.sup;
+                            result.push(*c);
                         }
 
-                        Trace::FromOutlivesConstraint(c) => {
+                        Trace::FromStatic(sub) => {
+                            let c = OutlivesConstraint {
+                                sup: fr_static,
+                                sub,
+                                locations: Locations::All(DUMMY_SP),
+                                span: DUMMY_SP,
+                                category: ConstraintCategory::Internal,
+                                variance_info: ty::VarianceDiagInfo::default(),
+                                from_closure: false,
+                            };
+                            p = c.sup;
+                            result.push(c);
+                        }
+
+                        Trace::FromMember(sup, sub, span) => {
+                            let c = OutlivesConstraint {
+                                sup,
+                                sub,
+                                locations: Locations::All(span),
+                                span,
+                                category: ConstraintCategory::OpaqueType,
+                                variance_info: ty::VarianceDiagInfo::default(),
+                                from_closure: false,
+                            };
                             p = c.sup;
                             result.push(c);
                         }
@@ -1798,6 +1828,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                             result.reverse();
                             return Some((result, r));
                         }
+
+                        Trace::NotVisited => {
+                            bug!("found unvisited region {:?} on path to {:?}", p, r)
+                        }
                     }
                 }
             }
@@ -1808,45 +1842,42 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             // A constraint like `'r: 'x` can come from our constraint
             // graph.
-            let fr_static = self.universal_regions().fr_static;
-            let outgoing_edges_from_graph =
-                self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static);
 
             // Always inline this closure because it can be hot.
-            let mut handle_constraint = #[inline(always)]
-            |constraint: OutlivesConstraint<'tcx>| {
-                debug_assert_eq!(constraint.sup, r);
-                let sub_region = constraint.sub;
-                if let Trace::NotVisited = context[sub_region] {
-                    context[sub_region] = Trace::FromOutlivesConstraint(constraint);
-                    deque.push_back(sub_region);
+            let mut handle_trace = #[inline(always)]
+            |sub, trace| {
+                if let Trace::NotVisited = context[sub] {
+                    context[sub] = trace;
+                    deque.push_back(sub);
                 }
             };
 
-            // This loop can be hot.
-            for constraint in outgoing_edges_from_graph {
-                if matches!(constraint.category, ConstraintCategory::IllegalUniverse) {
-                    debug!("Ignoring illegal universe constraint: {constraint:?}");
-                    continue;
+            // If this is the `'static` region and the graph's direction is normal, then set up the
+            // Edges iterator to return all regions (#53178).
+            if r == fr_static && self.constraint_graph.is_normal() {
+                for sub in self.constraint_graph.outgoing_edges_from_static() {
+                    handle_trace(sub, Trace::FromStatic(sub));
+                }
+            } else {
+                let edges = self.constraint_graph.outgoing_edges_from_graph(r, &self.constraints);
+                // This loop can be hot.
+                for constraint in edges {
+                    if matches!(constraint.category, ConstraintCategory::IllegalUniverse) {
+                        debug!("Ignoring illegal universe constraint: {constraint:?}");
+                        continue;
+                    }
+                    debug_assert_eq!(constraint.sup, r);
+                    handle_trace(constraint.sub, Trace::FromGraph(constraint));
                 }
-                handle_constraint(constraint);
             }
 
             // Member constraints can also give rise to `'r: 'x` edges that
             // were not part of the graph initially, so watch out for those.
             // (But they are extremely rare; this loop is very cold.)
             for constraint in self.applied_member_constraints(self.constraint_sccs.scc(r)) {
+                let sub = constraint.min_choice;
                 let p_c = &self.member_constraints[constraint.member_constraint_index];
-                let constraint = OutlivesConstraint {
-                    sup: r,
-                    sub: constraint.min_choice,
-                    locations: Locations::All(p_c.definition_span),
-                    span: p_c.definition_span,
-                    category: ConstraintCategory::OpaqueType,
-                    variance_info: ty::VarianceDiagInfo::default(),
-                    from_closure: false,
-                };
-                handle_constraint(constraint);
+                handle_trace(sub, Trace::FromMember(r, sub, p_c.definition_span));
             }
         }
 
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 3b48ca305c4..8dff40ba6ac 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -1,4 +1,4 @@
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
 use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
@@ -88,7 +88,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
     pub(crate) fn apply_closure_requirements(
         &mut self,
         closure_requirements: &ClosureRegionRequirements<'tcx>,
-        closure_def_id: DefId,
+        closure_def_id: LocalDefId,
         closure_args: ty::GenericArgsRef<'tcx>,
     ) {
         // Extract the values of the free regions in `closure_args`
@@ -98,7 +98,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             self.tcx,
             closure_args,
             closure_requirements.num_external_vids,
-            closure_def_id.expect_local(),
+            closure_def_id,
         );
         debug!(?closure_mapping);
 
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index dc35d5eb89c..32d398dc160 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -610,7 +610,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
             Err(ErrorGuaranteed { .. }) => {
                 // We don't run dropck on HIR, and dropck looks inside fields of
                 // types, so there's no guarantee that it succeeds. We also
-                // can't rely on the the `ErrorGuaranteed` from `fully_perform` here
+                // can't rely on the `ErrorGuaranteed` from `fully_perform` here
                 // because it comes from delay_span_bug.
                 //
                 // Do this inside of a probe because we don't particularly care (or want)
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 480d90932b9..c1e23cb5411 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -328,9 +328,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
-        debug!(?constant, ?location, "visit_const_operand");
-
         self.super_const_operand(constant, location);
         let ty = constant.const_.ty();
 
@@ -339,14 +338,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
             self.typeck.constraints.liveness_constraints.add_location(live_region_vid, location);
         });
 
-        // HACK(compiler-errors): Constants that are gathered into Body.required_consts
-        // have their locations erased...
-        let locations = if location != Location::START {
-            location.to_locations()
-        } else {
-            Locations::All(constant.span)
-        };
-
+        let locations = location.to_locations();
         if let Some(annotation_index) = constant.user_ty {
             if let Err(terr) = self.typeck.relate_type_and_user_type(
                 constant.const_.ty(),
@@ -491,9 +483,28 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_body(&mut self, body: &Body<'tcx>) {
-        // The types of local_decls are checked above which is called in super_body.
-        self.super_body(body);
+        // We intentionally do not recurse into `body.required_consts` or
+        // `body.mentioned_items` here as the MIR at this phase should still
+        // refer to all items and we don't want to check them multiple times.
+
+        for (local, local_decl) in body.local_decls.iter_enumerated() {
+            self.visit_local_decl(local, local_decl);
+        }
+
+        for (block, block_data) in body.basic_blocks.iter_enumerated() {
+            let mut location = Location { block, statement_index: 0 };
+            for stmt in &block_data.statements {
+                if !stmt.source_info.span.is_dummy() {
+                    self.last_span = stmt.source_info.span;
+                }
+                self.visit_statement(stmt, location);
+                location.statement_index += 1;
+            }
+
+            self.visit_terminator(block_data.terminator(), location);
+        }
     }
 }
 
@@ -2582,7 +2593,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 ConstraintCategory::Boring, // same as above.
                 self.constraints,
             )
-            .apply_closure_requirements(closure_requirements, def_id.to_def_id(), args);
+            .apply_closure_requirements(closure_requirements, def_id, args);
         }
 
         // Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589.
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index bb9dc651cec..a949ab94f3a 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::AssignOp(_, _, _)
             | ExprKind::Gen(_, _, _, _)
             | ExprKind::Await(_, _)
+            | ExprKind::Use(_, _)
             | ExprKind::Block(_, _)
             | ExprKind::Break(_, _)
             | ExprKind::Closure(_)
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 6d9c3575657..7b5c4a159b0 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -286,7 +286,7 @@ mod llvm_enzyme {
         let orig_annotatable: Annotatable = match item {
             Annotatable::Item(ref mut iitem) => {
                 if !iitem.attrs.iter().any(|a| a.id == attr.id) {
-                    iitem.attrs.push(attr.clone());
+                    iitem.attrs.push(attr);
                 }
                 if !iitem.attrs.iter().any(|a| a.id == inline_never.id) {
                     iitem.attrs.push(inline_never.clone());
@@ -295,7 +295,7 @@ mod llvm_enzyme {
             }
             Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => {
                 if !assoc_item.attrs.iter().any(|a| a.id == attr.id) {
-                    assoc_item.attrs.push(attr.clone());
+                    assoc_item.attrs.push(attr);
                 }
                 if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) {
                     assoc_item.attrs.push(inline_never.clone());
@@ -322,7 +322,7 @@ mod llvm_enzyme {
         let d_annotatable = if is_impl {
             let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
             let d_fn = P(ast::AssocItem {
-                attrs: thin_vec![d_attr.clone(), inline_never],
+                attrs: thin_vec![d_attr, inline_never],
                 id: ast::DUMMY_NODE_ID,
                 span,
                 vis,
@@ -332,12 +332,8 @@ mod llvm_enzyme {
             });
             Annotatable::AssocItem(d_fn, Impl)
         } else {
-            let mut d_fn = ecx.item(
-                span,
-                d_ident,
-                thin_vec![d_attr.clone(), inline_never],
-                ItemKind::Fn(asdf),
-            );
+            let mut d_fn =
+                ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
             d_fn.vis = vis;
             Annotatable::Item(d_fn)
         };
@@ -446,7 +442,7 @@ mod llvm_enzyme {
 
         if primal_ret && n_active == 0 && x.mode.is_rev() {
             // We only have the primal ret.
-            body.stmts.push(ecx.stmt_expr(black_box_primal_call.clone()));
+            body.stmts.push(ecx.stmt_expr(black_box_primal_call));
             return body;
         }
 
@@ -471,7 +467,7 @@ mod llvm_enzyme {
         if primal_ret {
             // We have both primal ret and active floats.
             // primal ret is first, by construction.
-            exprs.push(primal_call.clone());
+            exprs.push(primal_call);
         }
 
         // Now construct default placeholder for each active float.
@@ -538,16 +534,11 @@ mod llvm_enzyme {
                 return body;
             }
             [arg] => {
-                ret = ecx.expr_call(
-                    new_decl_span,
-                    blackbox_call_expr.clone(),
-                    thin_vec![arg.clone()],
-                );
+                ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![arg.clone()]);
             }
             args => {
                 let ret_tuple: P<ast::Expr> = ecx.expr_tuple(span, args.into());
-                ret =
-                    ecx.expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![ret_tuple]);
+                ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![ret_tuple]);
             }
         }
         assert!(has_ret(&d_sig.decl.output));
@@ -567,7 +558,7 @@ mod llvm_enzyme {
             let args: ThinVec<_> =
                 idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();
             let self_expr = ecx.expr_self(span);
-            ecx.expr_method_call(span, self_expr, primal, args.clone())
+            ecx.expr_method_call(span, self_expr, primal, args)
         } else {
             let args: ThinVec<_> =
                 idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 6dbd8a7ac01..12654001a1e 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -711,11 +711,9 @@ fn report_missing_placeholders(
                     };
 
                     let pos = sub.position();
-                    let sub = String::from(sub.as_str());
-                    if explained.contains(&sub) {
+                    if !explained.insert(sub.to_string()) {
                         continue;
                     }
-                    explained.insert(sub);
 
                     if !found_foreign {
                         found_foreign = true;
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 866ec72f116..13d5b42942a 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -12,14 +12,16 @@ pub(crate) mod printf {
         Escape((usize, usize)),
     }
 
-    impl<'a> Substitution<'a> {
-        pub(crate) fn as_str(&self) -> &str {
+    impl ToString for Substitution<'_> {
+        fn to_string(&self) -> String {
             match self {
-                Substitution::Format(fmt) => fmt.span,
-                Substitution::Escape(_) => "%%",
+                Substitution::Format(fmt) => fmt.span.into(),
+                Substitution::Escape(_) => "%%".into(),
             }
         }
+    }
 
+    impl Substitution<'_> {
         pub(crate) fn position(&self) -> InnerSpan {
             match self {
                 Substitution::Format(fmt) => fmt.position,
@@ -627,15 +629,17 @@ pub(crate) mod shell {
         Escape((usize, usize)),
     }
 
-    impl Substitution<'_> {
-        pub(crate) fn as_str(&self) -> String {
+    impl ToString for Substitution<'_> {
+        fn to_string(&self) -> String {
             match self {
                 Substitution::Ordinal(n, _) => format!("${n}"),
                 Substitution::Name(n, _) => format!("${n}"),
                 Substitution::Escape(_) => "$$".into(),
             }
         }
+    }
 
+    impl Substitution<'_> {
         pub(crate) fn position(&self) -> InnerSpan {
             let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
             InnerSpan::new(pos.0, pos.1)
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 6933ca09349..ba63b185e09 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -60,6 +60,7 @@ pub fn inject(
             Edition2018 => sym::rust_2018,
             Edition2021 => sym::rust_2021,
             Edition2024 => sym::rust_2024,
+            EditionFuture => sym::rust_future,
         }])
         .map(|&symbol| Ident::new(symbol, span))
         .collect();
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
index c2027863b00..754025ff49d 100644
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
@@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644
 --- a/library/alloc/Cargo.toml
 +++ b/library/alloc/Cargo.toml
 @@ -11,7 +11,7 @@ test = { path = "../test" }
- edition = "2021"
+ bench = false
  
  [dependencies]
  core = { path = "../core", public = true }
 -compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
 +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] }
  
- [dev-dependencies]
- rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+ [features]
+ compiler-builtins-mem = ['compiler_builtins/mem']
 -- 
 2.34.1
 
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 717baebcd8c..9fe6baa3d25 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -16,7 +16,7 @@ use crate::context::CodegenCx;
 use crate::intrinsic::ArgAbiExt;
 use crate::type_of::LayoutGccExt;
 
-impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+impl AbiBuilderMethods for Builder<'_, '_, '_> {
     fn get_param(&mut self, index: usize) -> Self::Value {
         let func = self.current_func();
         let param = func.get_param(index as i32);
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index c8b7616e645..6573b5b165e 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -2439,9 +2439,5 @@ fn get_maybe_pointer_size(value: RValue<'_>) -> u32 {
 #[cfg(not(feature = "master"))]
 fn get_maybe_pointer_size(value: RValue<'_>) -> u32 {
     let type_ = value.get_type();
-    if type_.get_pointee().is_some() {
-        std::mem::size_of::<*const ()>() as _
-    } else {
-        type_.get_size()
-    }
+    if type_.get_pointee().is_some() { size_of::<*const ()>() as _ } else { type_.get_size() }
 }
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 628e34badf9..a63da6b6e27 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -59,7 +59,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool {
     typ.get_pointee().is_some()
 }
 
-impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
     fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
         if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
     }
@@ -257,7 +257,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
     }
 
-    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
         const_alloc_to_gcc(self, alloc)
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index fb0ca31c543..c514b7a428b 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -302,9 +302,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 }
 
-pub fn const_alloc_to_gcc<'gcc, 'tcx>(
-    cx: &CodegenCx<'gcc, 'tcx>,
-    alloc: ConstAllocation<'tcx>,
+pub fn const_alloc_to_gcc<'gcc>(
+    cx: &CodegenCx<'gcc, '_>,
+    alloc: ConstAllocation<'_>,
 ) -> RValue<'gcc> {
     let alloc = alloc.inner();
     let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index cb08723431a..4e0a250b550 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -123,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
     fn type_i8(&self) -> Type<'gcc> {
         self.i8_type
     }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 8c75125e009..71059338151 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -654,7 +654,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
     }
 }
 
-impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
+impl AbiBuilderMethods for Builder<'_, '_, '_> {
     fn get_param(&mut self, index: usize) -> Self::Value {
         llvm::get_param(self.llfn(), index as c_uint)
     }
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 66723cbf882..e614115f64b 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -3,33 +3,31 @@ use rustc_ast::expand::allocator::{
     ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
     alloc_error_handler_name, default_fn_name, global_fn_name,
 };
+use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
 
-use crate::common::AsCCharPtr;
-use crate::llvm::{self, Context, False, Module, True, Type};
-use crate::{ModuleLlvm, attributes, debuginfo};
+use crate::builder::SBuilder;
+use crate::declare::declare_simple_fn;
+use crate::llvm::{self, False, True, Type};
+use crate::{SimpleCx, attributes, debuginfo};
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
-    module_llvm: &mut ModuleLlvm,
+    cx: SimpleCx<'_>,
     module_name: &str,
     kind: AllocatorKind,
     alloc_error_handler_kind: AllocatorKind,
 ) {
-    let llcx = &*module_llvm.llcx;
-    let llmod = module_llvm.llmod();
-    let usize = unsafe {
-        match tcx.sess.target.pointer_width {
-            16 => llvm::LLVMInt16TypeInContext(llcx),
-            32 => llvm::LLVMInt32TypeInContext(llcx),
-            64 => llvm::LLVMInt64TypeInContext(llcx),
-            tws => bug!("Unsupported target word size for int: {}", tws),
-        }
+    let usize = match tcx.sess.target.pointer_width {
+        16 => cx.type_i16(),
+        32 => cx.type_i32(),
+        64 => cx.type_i64(),
+        tws => bug!("Unsupported target word size for int: {}", tws),
     };
-    let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) };
-    let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) };
+    let i8 = cx.type_i8();
+    let i8p = cx.type_ptr();
 
     if kind == AllocatorKind::Default {
         for method in ALLOCATOR_METHODS {
@@ -58,15 +56,14 @@ pub(crate) unsafe fn codegen(
             let from_name = global_fn_name(method.name);
             let to_name = default_fn_name(method.name);
 
-            create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false);
+            create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false);
         }
     }
 
     // rust alloc error handler
     create_wrapper_function(
         tcx,
-        llcx,
-        llmod,
+        &cx,
         "__rust_alloc_error_handler",
         alloc_error_handler_name(alloc_error_handler_kind),
         &[usize, usize], // size, align
@@ -77,21 +74,21 @@ pub(crate) unsafe fn codegen(
     unsafe {
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
-        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
+        let ll_g = cx.declare_global(name, i8);
         llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::set_initializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
-        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
+        let ll_g = cx.declare_global(name, i8);
         llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::set_initializer(ll_g, llval);
     }
 
     if tcx.sess.opts.debuginfo != DebugInfo::None {
-        let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
+        let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod);
         debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
         dbg_cx.finalize(tcx.sess);
     }
@@ -99,77 +96,64 @@ pub(crate) unsafe fn codegen(
 
 fn create_wrapper_function(
     tcx: TyCtxt<'_>,
-    llcx: &Context,
-    llmod: &Module,
+    cx: &SimpleCx<'_>,
     from_name: &str,
     to_name: &str,
     args: &[&Type],
     output: Option<&Type>,
     no_return: bool,
 ) {
-    unsafe {
-        let ty = llvm::LLVMFunctionType(
-            output.unwrap_or_else(|| llvm::LLVMVoidTypeInContext(llcx)),
-            args.as_ptr(),
-            args.len() as c_uint,
-            False,
-        );
-        let llfn = llvm::LLVMRustGetOrInsertFunction(
-            llmod,
-            from_name.as_c_char_ptr(),
-            from_name.len(),
-            ty,
-        );
-        let no_return = if no_return {
-            // -> ! DIFlagNoReturn
-            let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
-            attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
-            Some(no_return)
-        } else {
-            None
-        };
-
-        llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
-
-        if tcx.sess.must_emit_unwind_tables() {
-            let uwtable =
-                attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
-            attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
-        }
+    let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
+    let llfn = declare_simple_fn(
+        &cx,
+        from_name,
+        llvm::CallConv::CCallConv,
+        llvm::UnnamedAddr::Global,
+        llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        ty,
+    );
+    let no_return = if no_return {
+        // -> ! DIFlagNoReturn
+        let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
+        Some(no_return)
+    } else {
+        None
+    };
 
-        let callee =
-            llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty);
-        if let Some(no_return) = no_return {
-            // -> ! DIFlagNoReturn
-            attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
-        }
-        llvm::set_visibility(callee, llvm::Visibility::Hidden);
-
-        let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
-
-        let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
-        llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
-        let args = args
-            .iter()
-            .enumerate()
-            .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
-            .collect::<Vec<_>>();
-        let ret = llvm::LLVMBuildCallWithOperandBundles(
-            llbuilder,
-            ty,
-            callee,
-            args.as_ptr(),
-            args.len() as c_uint,
-            [].as_ptr(),
-            0 as c_uint,
-            c"".as_ptr(),
-        );
-        llvm::LLVMSetTailCall(ret, True);
-        if output.is_some() {
-            llvm::LLVMBuildRet(llbuilder, ret);
-        } else {
-            llvm::LLVMBuildRetVoid(llbuilder);
-        }
-        llvm::LLVMDisposeBuilder(llbuilder);
+    if tcx.sess.must_emit_unwind_tables() {
+        let uwtable =
+            attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
+        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
+    }
+
+    let callee = declare_simple_fn(
+        &cx,
+        to_name,
+        llvm::CallConv::CCallConv,
+        llvm::UnnamedAddr::Global,
+        llvm::Visibility::Hidden,
+        ty,
+    );
+    if let Some(no_return) = no_return {
+        // -> ! DIFlagNoReturn
+        attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
+    }
+    llvm::set_visibility(callee, llvm::Visibility::Hidden);
+
+    let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
+
+    let mut bx = SBuilder::build(&cx, llbb);
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| llvm::get_param(llfn, i as c_uint))
+        .collect::<Vec<_>>();
+    let ret = bx.call(ty, callee, &args, None);
+    llvm::LLVMSetTailCall(ret, True);
+    if output.is_some() {
+        bx.ret(ret);
+    } else {
+        bx.ret_void()
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index e8a69743157..88daa025740 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -1,6 +1,5 @@
 use std::assert_matches::assert_matches;
 
-use libc::{c_char, c_uint};
 use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::mir::operand::OperandValue;
@@ -483,12 +482,13 @@ pub(crate) fn inline_asm_call<'ll>(
 
     debug!("Asm Output Type: {:?}", output);
     let fty = bx.cx.type_func(&argtys, output);
-    unsafe {
-        // Ask LLVM to verify that the constraints are well-formed.
-        let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len());
-        debug!("constraint verification result: {:?}", constraints_ok);
-        if constraints_ok {
-            let v = llvm::LLVMRustInlineAsm(
+    // Ask LLVM to verify that the constraints are well-formed.
+    let constraints_ok =
+        unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) };
+    debug!("constraint verification result: {:?}", constraints_ok);
+    if constraints_ok {
+        let v = unsafe {
+            llvm::LLVMRustInlineAsm(
                 fty,
                 asm.as_c_char_ptr(),
                 asm.len(),
@@ -498,54 +498,50 @@ pub(crate) fn inline_asm_call<'ll>(
                 alignstack,
                 dia,
                 can_throw,
-            );
-
-            let call = if !labels.is_empty() {
-                assert!(catch_funclet.is_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, None)
-            } else {
-                bx.call(fty, None, None, v, inputs, None, None)
-            };
+            )
+        };
 
-            // Store mark in a metadata node so we can map LLVM errors
-            // back to source locations. See #17552.
-            let key = "srcloc";
-            let kind = llvm::LLVMGetMDKindIDInContext(
-                bx.llcx,
-                key.as_ptr().cast::<c_char>(),
-                key.len() as c_uint,
-            );
+        let call = if !labels.is_empty() {
+            assert!(catch_funclet.is_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, None)
+        } else {
+            bx.call(fty, None, None, v, inputs, None, None)
+        };
 
-            // `srcloc` contains one 64-bit integer for each line of assembly code,
-            // where the lower 32 bits hold the lo byte position and the upper 32 bits
-            // hold the hi byte position.
-            let mut srcloc = vec![];
-            if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
-                // LLVM inserts an extra line to add the ".intel_syntax", so add
-                // a dummy srcloc entry for it.
-                //
-                // Don't do this if we only have 1 line span since that may be
-                // due to the asm template string coming from a macro. LLVM will
-                // default to the first srcloc for lines that don't have an
-                // associated srcloc.
-                srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
-            }
-            srcloc.extend(line_spans.iter().map(|span| {
-                llvm::LLVMValueAsMetadata(bx.const_u64(
-                    u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32),
-                ))
-            }));
-            let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len());
-            let md = llvm::LLVMMetadataAsValue(&bx.llcx, md);
-            llvm::LLVMSetMetadata(call, kind, md);
+        // Store mark in a metadata node so we can map LLVM errors
+        // back to source locations. See #17552.
+        let key = "srcloc";
+        let kind = bx.get_md_kind_id(key);
 
-            Some(call)
-        } else {
-            // LLVM has detected an issue with our constraints, bail out
-            None
+        // `srcloc` contains one 64-bit integer for each line of assembly code,
+        // where the lower 32 bits hold the lo byte position and the upper 32 bits
+        // hold the hi byte position.
+        let mut srcloc = vec![];
+        if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
+            // LLVM inserts an extra line to add the ".intel_syntax", so add
+            // a dummy srcloc entry for it.
+            //
+            // Don't do this if we only have 1 line span since that may be
+            // due to the asm template string coming from a macro. LLVM will
+            // default to the first srcloc for lines that don't have an
+            // associated srcloc.
+            srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
         }
+        srcloc.extend(line_spans.iter().map(|span| {
+            llvm::LLVMValueAsMetadata(
+                bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
+            )
+        }));
+        let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
+        let md = bx.get_metadata_value(md);
+        llvm::LLVMSetMetadata(call, kind, md);
+
+        Some(call)
+    } else {
+        // LLVM has detected an issue with our constraints, bail out
+        None
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 3f20350d0ef..55d34f5f2ef 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -30,7 +30,7 @@ use tracing::{debug, instrument};
 
 use crate::abi::FnAbiLlvmExt;
 use crate::common::Funclet;
-use crate::context::{CodegenCx, SimpleCx};
+use crate::context::{CodegenCx, FullCx, GenericCx, SCx};
 use crate::llvm::{
     self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True,
 };
@@ -40,15 +40,15 @@ use crate::value::Value;
 use crate::{attributes, llvm_util};
 
 #[must_use]
-pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> {
+pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SCx<'ll>>> {
     pub llbuilder: &'ll mut llvm::Builder<'ll>,
-    pub cx: &'a CX,
+    pub cx: &'a GenericCx<'ll, CX>,
 }
 
-pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>;
-pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>;
+pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SCx<'ll>>;
+pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, FullCx<'ll, 'tcx>>;
 
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
     fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
@@ -57,7 +57,7 @@ impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
 }
 
 impl<'a, 'll> SBuilder<'a, 'll> {
-    fn call(
+    pub(crate) fn call(
         &mut self,
         llty: &'ll Type,
         llfn: &'ll Value,
@@ -87,79 +87,36 @@ impl<'a, 'll> SBuilder<'a, 'll> {
         };
         call
     }
+}
 
-    fn with_scx(scx: &'a SimpleCx<'ll>) -> Self {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+    fn with_cx(scx: &'a GenericCx<'ll, CX>) -> Self {
         // Create a fresh builder from the simple context.
-        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) };
-        SBuilder { llbuilder, cx: scx }
+        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.deref().borrow().llcx) };
+        GenericBuilder { llbuilder, cx: scx }
     }
-}
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+
     pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
     }
 
-    fn ret_void(&mut self) {
-        unsafe {
-            llvm::LLVMBuildRetVoid(self.llbuilder);
-        }
+    pub(crate) fn ret_void(&mut self) {
+        llvm::LLVMBuildRetVoid(self.llbuilder);
     }
 
-    fn ret(&mut self, v: &'ll Value) {
+    pub(crate) fn ret(&mut self, v: &'ll Value) {
         unsafe {
             llvm::LLVMBuildRet(self.llbuilder, v);
         }
     }
-}
-impl<'a, 'll> SBuilder<'a, 'll> {
-    fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> {
-        let bx = SBuilder::with_scx(cx);
+
+    pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self {
+        let bx = Self::with_cx(cx);
         unsafe {
             llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
         }
         bx
     }
-
-    fn check_call<'b>(
-        &mut self,
-        typ: &str,
-        fn_ty: &'ll Type,
-        llfn: &'ll Value,
-        args: &'b [&'ll Value],
-    ) -> Cow<'b, [&'ll Value]> {
-        assert!(
-            self.cx.type_kind(fn_ty) == TypeKind::Function,
-            "builder::{typ} not passed a function, but {fn_ty:?}"
-        );
-
-        let param_tys = self.cx.func_params_types(fn_ty);
-
-        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
-            .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
-
-        if all_args_match {
-            return Cow::Borrowed(args);
-        }
-
-        let casted_args: Vec<_> = iter::zip(param_tys, args)
-            .enumerate()
-            .map(|(i, (expected_ty, &actual_val))| {
-                let actual_ty = self.cx.val_ty(actual_val);
-                if expected_ty != actual_ty {
-                    debug!(
-                        "type mismatch in function call of {:?}. \
-                            Expected {:?} for param {}, got {:?}; injecting bitcast",
-                        llfn, expected_ty, i, actual_ty
-                    );
-                    self.bitcast(actual_val, expected_ty)
-                } else {
-                    actual_val
-                }
-            })
-            .collect();
-
-        Cow::Owned(casted_args)
-    }
 }
 
 /// Empty string, to be used where LLVM expects an instruction name, indicating
@@ -167,17 +124,17 @@ impl<'a, 'll> SBuilder<'a, 'll> {
 // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
 const UNNAMED: *const c_char = c"".as_ptr();
 
-impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> {
-    type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
-    type Metadata = <CodegenCx<'ll, 'tcx> as BackendTypes>::Metadata;
-    type Function = <CodegenCx<'ll, 'tcx> as BackendTypes>::Function;
-    type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock;
-    type Type = <CodegenCx<'ll, 'tcx> as BackendTypes>::Type;
-    type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;
-
-    type DIScope = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIScope;
-    type DILocation = <CodegenCx<'ll, 'tcx> as BackendTypes>::DILocation;
-    type DIVariable = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIVariable;
+impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericBuilder<'_, 'll, CX> {
+    type Value = <GenericCx<'ll, CX> as BackendTypes>::Value;
+    type Metadata = <GenericCx<'ll, CX> as BackendTypes>::Metadata;
+    type Function = <GenericCx<'ll, CX> as BackendTypes>::Function;
+    type BasicBlock = <GenericCx<'ll, CX> as BackendTypes>::BasicBlock;
+    type Type = <GenericCx<'ll, CX> as BackendTypes>::Type;
+    type Funclet = <GenericCx<'ll, CX> as BackendTypes>::Funclet;
+
+    type DIScope = <GenericCx<'ll, CX> as BackendTypes>::DIScope;
+    type DILocation = <GenericCx<'ll, CX> as BackendTypes>::DILocation;
+    type DIVariable = <GenericCx<'ll, CX> as BackendTypes>::DIVariable;
 }
 
 impl abi::HasDataLayout for Builder<'_, '_, '_> {
@@ -293,9 +250,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn ret_void(&mut self) {
-        unsafe {
-            llvm::LLVMBuildRetVoid(self.llbuilder);
-        }
+        llvm::LLVMBuildRetVoid(self.llbuilder);
     }
 
     fn ret(&mut self, v: &'ll Value) {
@@ -356,8 +311,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // This function handles switch instructions with more than 2 targets and it needs to
         // emit branch weights metadata instead of using the intrinsic.
         // The values 1 and 2000 are the same as the values used by the `llvm.expect` intrinsic.
-        let cold_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(1)) };
-        let hot_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)) };
+        let cold_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(1));
+        let hot_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(2000));
         let weight =
             |is_cold: bool| -> &Metadata { if is_cold { cold_weight } else { hot_weight } };
 
@@ -1476,26 +1431,12 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
 }
 
 impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
-    fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> {
-        let bx = Builder::with_cx(cx);
-        unsafe {
-            llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
-        }
-        bx
-    }
-
-    fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
-        // Create a fresh builder from the crate context.
-        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) };
-        Builder { llbuilder, cx }
-    }
-
     pub(crate) fn llfn(&self) -> &'ll Value {
         unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) }
     }
 }
 
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     fn position_at_start(&mut self, llbb: &'ll BasicBlock) {
         unsafe {
             llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
@@ -1525,7 +1466,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         }
     }
 }
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
         unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
     }
@@ -1626,9 +1567,7 @@ impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
         let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
         ret.expect("LLVM does not have support for catchret")
     }
-}
 
-impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     fn check_call<'b>(
         &mut self,
         typ: &str,
@@ -1643,7 +1582,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         let param_tys = self.cx.func_params_types(fn_ty);
 
-        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.val_ty(v)))
+        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
             .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
 
         if all_args_match {
@@ -1653,7 +1592,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         let casted_args: Vec<_> = iter::zip(param_tys, args)
             .enumerate()
             .map(|(i, (expected_ty, &actual_val))| {
-                let actual_ty = self.val_ty(actual_val);
+                let actual_ty = self.cx.val_ty(actual_val);
                 if expected_ty != actual_ty {
                     debug!(
                         "type mismatch in function call of {:?}. \
@@ -1669,12 +1608,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         Cow::Owned(casted_args)
     }
-}
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+
     pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
     }
 }
+
 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);
@@ -1694,7 +1633,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
     }
 }
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn phi(
         &mut self,
         ty: &'ll Type,
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 2c7899975e3..71705ecb4d0 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -3,6 +3,7 @@ use std::ptr;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::back::write::ModuleConfig;
+use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
 use rustc_errors::FatalError;
 use tracing::{debug, trace};
 
@@ -286,7 +287,8 @@ pub(crate) fn differentiate<'ll>(
     }
 
     let diag_handler = cgcx.create_dcx();
-    let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx };
+
+    let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size);
 
     // First of all, did the user try to use autodiff without using the -Zautodiff=Enable flag?
     if !diff_items.is_empty()
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index f264e3419e4..457e5452ce9 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -1,5 +1,7 @@
 //! Code that is useful in various codegen modules.
 
+use std::borrow::Borrow;
+
 use libc::{c_char, c_uint};
 use rustc_abi as abi;
 use rustc_abi::Primitive::Pointer;
@@ -18,6 +20,7 @@ use tracing::debug;
 
 use crate::consts::const_alloc_to_llvm;
 pub(crate) use crate::context::CodegenCx;
+use crate::context::{GenericCx, SCx};
 use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True};
 use crate::type_::Type;
 use crate::value::Value;
@@ -81,7 +84,7 @@ impl<'ll> Funclet<'ll> {
     }
 }
 
-impl<'ll> BackendTypes for CodegenCx<'ll, '_> {
+impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericCx<'ll, CX> {
     type Value = &'ll Value;
     type Metadata = &'ll Metadata;
     // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`.
@@ -118,7 +121,7 @@ impl<'ll> CodegenCx<'ll, '_> {
     }
 }
 
-impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
     fn const_null(&self, t: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMConstNull(t) }
     }
@@ -342,7 +345,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
-    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
         const_alloc_to_llvm(self, alloc, /*static*/ false)
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 330e8a8f406..a4e5749b3ac 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -16,7 +16,6 @@ use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::{bug, span_bug};
-use rustc_session::config::Lto;
 use tracing::{debug, instrument, trace};
 
 use crate::common::{AsCCharPtr, CodegenCx};
@@ -344,11 +343,11 @@ impl<'ll> CodegenCx<'ll, '_> {
                 // Local definitions can never be imported, so we must not apply
                 // the DLLImport annotation.
                 && !dso_local
-                // ThinLTO can't handle this workaround in all cases, so we don't
-                // emit the attrs. Instead we make them unnecessary by disallowing
-                // dynamic linking when linker plugin based LTO is enabled.
-                && !self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
-                && self.tcx.sess.lto() != Lto::Thin;
+                // Linker plugin ThinLTO doesn't create the self-dllimport Rust uses for rlibs
+                // as the code generation happens out of process. Instead we assume static linkage
+                // and disallow dynamic linking when linker plugin based LTO is enabled.
+                // Regular in-process ThinLTO doesn't need this workaround.
+                && !self.tcx.sess.opts.cg.linker_plugin_lto.enabled();
 
             // If this assertion triggers, there's something wrong with commandline
             // argument validation.
@@ -490,7 +489,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                         llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
                     let data = [section, alloc];
                     let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
-                    let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
+                    let val = self.get_metadata_value(meta);
                     llvm::LLVMAddNamedMetadataOperand(
                         self.llmod,
                         c"wasm.custom_sections".as_ptr(),
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index ed8426ae197..9f8ec0ea526 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1,13 +1,13 @@
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
 use std::ffi::{CStr, c_char, c_uint};
+use std::marker::PhantomData;
 use std::ops::Deref;
 use std::str;
 
-use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
+use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx};
 use rustc_codegen_ssa::back::versioned_llvm_target;
 use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
-use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::errors as ssa_errors;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
@@ -32,9 +32,9 @@ use smallvec::SmallVec;
 
 use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
-use crate::common::{self, AsCCharPtr};
+use crate::common::AsCCharPtr;
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
-use crate::llvm::{Metadata, MetadataType};
+use crate::llvm::Metadata;
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
@@ -43,18 +43,19 @@ use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
 /// However, there are various cx related functions which we want to be available to the builder and
 /// other compiler pieces. Here we define a small subset which has enough information and can be
 /// moved around more freely.
-pub(crate) struct SimpleCx<'ll> {
+pub(crate) struct SCx<'ll> {
     pub llmod: &'ll llvm::Module,
     pub llcx: &'ll llvm::Context,
+    pub isize_ty: &'ll Type,
 }
 
-impl<'ll> Borrow<SimpleCx<'ll>> for CodegenCx<'ll, '_> {
-    fn borrow(&self) -> &SimpleCx<'ll> {
+impl<'ll> Borrow<SCx<'ll>> for FullCx<'ll, '_> {
+    fn borrow(&self) -> &SCx<'ll> {
         &self.scx
     }
 }
 
-impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> Deref for FullCx<'ll, 'tcx> {
     type Target = SimpleCx<'ll>;
 
     #[inline]
@@ -63,10 +64,25 @@ impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
     }
 }
 
+pub(crate) struct GenericCx<'ll, T: Borrow<SCx<'ll>>>(T, PhantomData<SCx<'ll>>);
+
+impl<'ll, T: Borrow<SCx<'ll>>> Deref for GenericCx<'ll, T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+pub(crate) type SimpleCx<'ll> = GenericCx<'ll, SCx<'ll>>;
+
 /// There is one `CodegenCx` per codegen unit. Each one has its own LLVM
 /// `llvm::Context` so that several codegen units may be processed in parallel.
 /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
-pub(crate) struct CodegenCx<'ll, 'tcx> {
+pub(crate) type CodegenCx<'ll, 'tcx> = GenericCx<'ll, FullCx<'ll, 'tcx>>;
+
+pub(crate) struct FullCx<'ll, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
     pub scx: SimpleCx<'ll>,
     pub use_dll_storage_attrs: bool,
@@ -104,8 +120,6 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
     /// Mapping of scalar types to llvm types.
     pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>,
 
-    pub isize_ty: &'ll Type,
-
     /// Extra per-CGU codegen state needed when coverage instrumentation is enabled.
     pub coverage_cx: Option<coverageinfo::CguCoverageContext<'ll, 'tcx>>,
     pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
@@ -579,33 +593,33 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             None
         };
 
-        let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits());
-
-        CodegenCx {
-            tcx,
-            scx: SimpleCx { llcx, llmod },
-            use_dll_storage_attrs,
-            tls_model,
-            codegen_unit,
-            instances: Default::default(),
-            vtables: Default::default(),
-            const_str_cache: Default::default(),
-            const_globals: Default::default(),
-            statics_to_rauw: RefCell::new(Vec::new()),
-            used_statics: RefCell::new(Vec::new()),
-            compiler_used_statics: RefCell::new(Vec::new()),
-            type_lowering: Default::default(),
-            scalar_lltypes: Default::default(),
-            isize_ty,
-            coverage_cx,
-            dbg_cx,
-            eh_personality: Cell::new(None),
-            eh_catch_typeinfo: Cell::new(None),
-            rust_try_fn: Cell::new(None),
-            intrinsics: Default::default(),
-            local_gen_sym_counter: Cell::new(0),
-            renamed_statics: Default::default(),
-        }
+        GenericCx(
+            FullCx {
+                tcx,
+                scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size),
+                use_dll_storage_attrs,
+                tls_model,
+                codegen_unit,
+                instances: Default::default(),
+                vtables: Default::default(),
+                const_str_cache: Default::default(),
+                const_globals: Default::default(),
+                statics_to_rauw: RefCell::new(Vec::new()),
+                used_statics: RefCell::new(Vec::new()),
+                compiler_used_statics: RefCell::new(Vec::new()),
+                type_lowering: Default::default(),
+                scalar_lltypes: Default::default(),
+                coverage_cx,
+                dbg_cx,
+                eh_personality: Cell::new(None),
+                eh_catch_typeinfo: Cell::new(None),
+                rust_try_fn: Cell::new(None),
+                intrinsics: Default::default(),
+                local_gen_sym_counter: Cell::new(0),
+                renamed_statics: Default::default(),
+            },
+            PhantomData,
+        )
     }
 
     pub(crate) fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> {
@@ -628,24 +642,32 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         llvm::set_section(g, c"llvm.metadata");
     }
 }
+
 impl<'ll> SimpleCx<'ll> {
-    pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
-        common::val_ty(v)
+    pub(crate) fn new(
+        llmod: &'ll llvm::Module,
+        llcx: &'ll llvm::Context,
+        pointer_size: Size,
+    ) -> Self {
+        let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits());
+        Self(SCx { llmod, llcx, isize_ty }, PhantomData)
     }
+}
 
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
-        unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
+        llvm::LLVMMetadataAsValue(self.llcx(), metadata)
     }
 
     pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
         let name = SmallCStr::new(name);
-        unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) }
+        unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) }
     }
 
-    pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 {
+    pub(crate) fn get_md_kind_id(&self, name: &str) -> llvm::MetadataKindId {
         unsafe {
             llvm::LLVMGetMDKindIDInContext(
-                self.llcx,
+                self.llcx(),
                 name.as_ptr() as *const c_char,
                 name.len() as c_uint,
             )
@@ -654,13 +676,9 @@ impl<'ll> SimpleCx<'ll> {
 
     pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> {
         Some(unsafe {
-            llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
+            llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
         })
     }
-
-    pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind {
-        unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
-    }
 }
 
 impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -1203,27 +1221,18 @@ impl CodegenCx<'_, '_> {
         name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
         name
     }
-
-    /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
-    pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
-        unsafe {
-            let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
-            llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
-        }
-    }
 }
 
-// This is a duplication of the set_metadata function above. However, so far it's the only one
-// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it
-// for the Builder.
-impl SimpleCx<'_> {
-    #[allow(unused)]
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
-    pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
-        unsafe {
-            let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
-            llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
-        }
+    pub(crate) fn set_metadata<'a>(
+        &self,
+        val: &'a Value,
+        kind_id: impl Into<llvm::MetadataKindId>,
+        md: &'ll Metadata,
+    ) {
+        let node = self.get_metadata_value(md);
+        llvm::LLVMSetMetadata(val, kind_id.into(), node);
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index c53ea6d4666..80e54bf045e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -8,7 +8,7 @@ use std::ffi::CString;
 
 use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
-    BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
+    BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods,
 };
 use rustc_middle::mir::coverage::{
     BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index e79662ebc64..2419ec1f888 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -11,6 +11,8 @@
 //! * Use define_* family of methods when you might be defining the Value.
 //! * When in doubt, define.
 
+use std::borrow::Borrow;
+
 use itertools::Itertools;
 use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
 use rustc_data_structures::fx::FxIndexSet;
@@ -22,7 +24,7 @@ use tracing::debug;
 
 use crate::abi::FnAbiLlvmExt;
 use crate::common::AsCCharPtr;
-use crate::context::{CodegenCx, SimpleCx};
+use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx};
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::Visibility;
 use crate::type_::Type;
@@ -81,16 +83,25 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
     llfn
 }
 
-impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     /// Declare a global value.
     ///
     /// If there’s a value with the same name already declared, the function will
     /// return its Value instead.
     pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
         debug!("declare_global(name={:?})", name);
-        unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) }
+        unsafe {
+            llvm::LLVMRustGetOrInsertGlobal(
+                (**self).borrow().llmod,
+                name.as_c_char_ptr(),
+                name.len(),
+                ty,
+            )
+        }
     }
+}
 
+impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     /// Declare a C ABI function.
     ///
     /// Only use this for foreign function ABIs and glue. For Rust functions use
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 0272667e223..660fc7ec4c4 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -649,7 +649,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
     fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value {
         // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
         // optimization pass replaces calls to this intrinsic with code to test type membership.
-        let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) };
+        let typeid = self.get_metadata_value(typeid);
         self.call_intrinsic("llvm.type.test", &[pointer, typeid])
     }
 
@@ -659,7 +659,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         vtable_byte_offset: u64,
         typeid: &'ll Metadata,
     ) -> Self::Value {
-        let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) };
+        let typeid = self.get_metadata_value(typeid);
         let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
         let type_checked_load =
             self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]);
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 8f72307eeba..e51d4852db2 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -28,6 +28,7 @@ use std::mem::ManuallyDrop;
 
 use back::owned_target_machine::OwnedTargetMachine;
 use back::write::{create_informational_target_machine, create_target_machine};
+use context::SimpleCx;
 use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
 pub(crate) use llvm_util::target_features_cfg;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -115,9 +116,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         kind: AllocatorKind,
         alloc_error_handler_kind: AllocatorKind,
     ) -> ModuleLlvm {
-        let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
+        let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
+        let cx =
+            SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size);
         unsafe {
-            allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
+            allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind);
         }
         module_llvm
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 25ca3498803..f6b23862907 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -3,13 +3,14 @@
 
 use libc::{c_char, c_uint};
 
+use super::MetadataKindId;
 use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
 use crate::llvm::Bool;
 
 #[link(name = "llvm-wrapper", kind = "static")]
 unsafe extern "C" {
     // Enzyme
-    pub(crate) fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
+    pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool;
     pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
     pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
     pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index e3d0b928c97..39087a4d6f4 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -976,6 +976,16 @@ pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void);
 pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
 pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void;
 
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct MetadataKindId(c_uint);
+
+impl From<MetadataType> for MetadataKindId {
+    fn from(value: MetadataType) -> Self {
+        Self(value as c_uint)
+    }
+}
+
 unsafe extern "C" {
     // Create and destroy contexts.
     pub(crate) fn LLVMContextDispose(C: &'static mut Context);
@@ -983,7 +993,7 @@ unsafe extern "C" {
         C: &Context,
         Name: *const c_char,
         SLen: c_uint,
-    ) -> c_uint;
+    ) -> MetadataKindId;
 
     // Create modules.
     pub(crate) fn LLVMModuleCreateWithNameInContext(
@@ -1050,9 +1060,9 @@ unsafe extern "C" {
     pub(crate) fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
     pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
     pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
-    pub(crate) fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+    pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value);
     pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
-    pub(crate) fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
+    pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
 
     // Operations on constants of any type
     pub(crate) fn LLVMConstNull(Ty: &Type) -> &Value;
@@ -1146,7 +1156,7 @@ unsafe extern "C" {
     pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
     pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
     pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
-    pub(crate) fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
+    pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
 
     // Operations on attributes
     pub(crate) fn LLVMCreateStringAttribute(
@@ -1203,7 +1213,7 @@ unsafe extern "C" {
     pub(crate) fn LLVMGetCurrentDebugLocation2<'a>(Builder: &Builder<'a>) -> Option<&'a Metadata>;
 
     // Terminators
-    pub(crate) fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
+    pub(crate) safe fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
     pub(crate) fn LLVMBuildRet<'a>(B: &Builder<'a>, V: &'a Value) -> &'a Value;
     pub(crate) fn LLVMBuildBr<'a>(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value;
     pub(crate) fn LLVMBuildCondBr<'a>(
@@ -1679,7 +1689,7 @@ unsafe extern "C" {
         Packed: Bool,
     );
 
-    pub(crate) fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
+    pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
 
     pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
 
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index d61ce417562..b89ce90d1a1 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -1,3 +1,4 @@
+use std::borrow::Borrow;
 use std::{fmt, ptr};
 
 use libc::{c_char, c_uint};
@@ -11,7 +12,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::callconv::{CastTarget, FnAbi};
 
 use crate::abi::{FnAbiLlvmExt, LlvmType};
-use crate::context::{CodegenCx, SimpleCx};
+use crate::context::{CodegenCx, GenericCx, SCx};
 pub(crate) use crate::llvm::Type;
 use crate::llvm::{Bool, False, Metadata, True};
 use crate::type_of::LayoutLlvmExt;
@@ -36,29 +37,29 @@ impl fmt::Debug for Type {
 }
 
 impl<'ll> CodegenCx<'ll, '_> {}
-impl<'ll> SimpleCx<'ll> {
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
         let name = SmallCStr::new(name);
-        unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
+        unsafe { llvm::LLVMStructCreateNamed(self.llcx(), name.as_ptr()) }
     }
 
     pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
         unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
     }
     pub(crate) fn type_void(&self) -> &'ll Type {
-        unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) }
     }
     pub(crate) fn type_token(&self) -> &'ll Type {
-        unsafe { llvm::LLVMTokenTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) }
     }
 
     pub(crate) fn type_metadata(&self) -> &'ll Type {
-        unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) }
     }
 
     ///x Creates an integer type with the given number of bits, e.g., i24
     pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
-        unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) }
+        unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) }
     }
 
     pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
@@ -121,19 +122,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         self.type_array(self.type_from_integer(unit), size / unit_size)
     }
 }
-impl<'ll> SimpleCx<'ll> {
+
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
+    pub(crate) fn llcx(&self) -> &'ll llvm::Context {
+        (**self).borrow().llcx
+    }
+
+    pub(crate) fn isize_ty(&self) -> &'ll Type {
+        (**self).borrow().isize_ty
+    }
+
     pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
         unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
     }
 
     pub(crate) fn type_i1(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt1TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt1TypeInContext(self.llcx()) }
     }
 
     pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type {
         unsafe {
             llvm::LLVMStructTypeInContext(
-                self.llcx,
+                self.llcx(),
                 els.as_ptr(),
                 els.len() as c_uint,
                 packed as Bool,
@@ -142,45 +152,45 @@ impl<'ll> SimpleCx<'ll> {
     }
 }
 
-impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> {
     fn type_i8(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt8TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt8TypeInContext(self.llcx()) }
     }
 
     fn type_i16(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt16TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt16TypeInContext(self.llcx()) }
     }
 
     fn type_i32(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt32TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt32TypeInContext(self.llcx()) }
     }
 
     fn type_i64(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt64TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) }
     }
 
     fn type_i128(&self) -> &'ll Type {
-        unsafe { llvm::LLVMIntTypeInContext(self.llcx, 128) }
+        unsafe { llvm::LLVMIntTypeInContext(self.llcx(), 128) }
     }
 
     fn type_isize(&self) -> &'ll Type {
-        self.isize_ty
+        self.isize_ty()
     }
 
     fn type_f16(&self) -> &'ll Type {
-        unsafe { llvm::LLVMHalfTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMHalfTypeInContext(self.llcx()) }
     }
 
     fn type_f32(&self) -> &'ll Type {
-        unsafe { llvm::LLVMFloatTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMFloatTypeInContext(self.llcx()) }
     }
 
     fn type_f64(&self) -> &'ll Type {
-        unsafe { llvm::LLVMDoubleTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMDoubleTypeInContext(self.llcx()) }
     }
 
     fn type_f128(&self) -> &'ll Type {
-        unsafe { llvm::LLVMFP128TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMFP128TypeInContext(self.llcx()) }
     }
 
     fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
@@ -196,7 +206,7 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type {
-        unsafe { llvm::LLVMPointerTypeInContext(self.llcx, address_space.0) }
+        unsafe { llvm::LLVMPointerTypeInContext(self.llcx(), address_space.0) }
     }
 
     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index f15d6fba506..95912b01600 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -18,6 +18,8 @@ codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing
 
 codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto
 
+codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument
+
 codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
 
 codegen_ssa_cgu_not_recorded =
@@ -52,6 +54,10 @@ codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$err
 codegen_ssa_error_writing_def_file =
     Error writing .DEF file: {$error}
 
+codegen_ssa_expected_name_value_pair = expected name value pair
+
+codegen_ssa_expected_one_argument = expected one argument
+
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
@@ -88,9 +94,17 @@ codegen_ssa_incorrect_cgu_reuse_type =
 
 codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
 
+codegen_ssa_invalid_argument = invalid argument
+    .help = valid inline arguments are `always` and `never`
+
+codegen_ssa_invalid_instruction_set = invalid instruction set specified
+
 codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
     .note = the attribute requires exactly one argument
 
+codegen_ssa_invalid_literal_value = invalid literal value
+    .label = value must be an integer between `0` and `255`
+
 codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
 
 codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
@@ -217,6 +231,8 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but
 
 codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
 
+codegen_ssa_multiple_instruction_set = cannot specify more than one instruction set
+
 codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
     .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
@@ -229,6 +245,11 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
 
 codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't
 
+codegen_ssa_null_on_export = `export_name` may not contain null characters
+
+codegen_ssa_out_of_range_integer = integer value out of range
+    .label = value must be between `0` and `255`
+
 codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
     .note = {$output}
 
@@ -236,6 +257,8 @@ codegen_ssa_read_file = failed to read file: {$message}
 
 codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
 
+codegen_ssa_requires_rust_abi = `#[track_caller]` requires Rust ABI
+
 codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib at `{$path}`: {$error}
 
 codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
@@ -356,6 +379,9 @@ codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
 
 codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
 
+codegen_ssa_unexpected_parameter_name = unexpected parameter name
+    .label = expected `{$prefix_nops}` or `{$entry_nops}`
+
 codegen_ssa_unknown_archive_kind =
     Don't know how to build archive of type: {$kind}
 
@@ -367,6 +393,8 @@ codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
 
 codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
 
+codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
+
 codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
 
 codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index a170b2e3b6a..7d9971c021d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1177,7 +1177,7 @@ mod win {
             let mut cp: u32 = 0;
             // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32.
             // But the API requires us to pass the data as though it's a [u16] string.
-            let len = std::mem::size_of::<u32>() / std::mem::size_of::<u16>();
+            let len = size_of::<u32>() / size_of::<u16>();
             let data = std::slice::from_raw_parts_mut(&mut cp as *mut u32 as *mut u16, len);
             let len_written = GetLocaleInfoEx(
                 LOCALE_NAME_SYSTEM_DEFAULT,
@@ -3382,6 +3382,35 @@ fn add_lld_args(
     // this, `wasm-component-ld`, which is overridden if this option is passed.
     if !sess.target.is_like_wasm {
         cmd.cc_arg("-fuse-ld=lld");
+
+        // On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some
+        // section garbage-collection features. For example, the somewhat popular `linkme` crate and
+        // its dependents rely in practice on this difference: when using lld, they need `-z
+        // nostart-stop-gc` to prevent encapsulation symbols and sections from being
+        // garbage-collected.
+        //
+        // More information about all this can be found in:
+        // - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order
+        // - https://lld.llvm.org/ELF/start-stop-gc
+        //
+        // So when using lld, we restore, for now, the traditional behavior to help migration, but
+        // will remove it in the future.
+        // Since this only disables an optimization, it shouldn't create issues, but is in theory
+        // slightly suboptimal. However, it:
+        // - doesn't have any visible impact on our benchmarks
+        // - reduces the need to disable lld for the crates that depend on this
+        //
+        // Note that lld can detect some cases where this difference is relied on, and emits a
+        // dedicated error to add this link arg. We could make use of this error to emit an FCW. As
+        // of writing this, we don't do it, because lld is already enabled by default on nightly
+        // without this mitigation: no working project would see the FCW, so we do this to help
+        // stabilization.
+        //
+        // FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the
+        // future.
+        if sess.target.llvm_target == "x86_64-unknown-linux-gnu" {
+            cmd.link_arg("-znostart-stop-gc");
+        }
     }
 
     if !flavor.is_gnu() {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 818edaf6603..a8405a2aec9 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1655,9 +1655,9 @@ impl<'a> Linker for AixLinker<'a> {
         }
     }
 
-    fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
+    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
         self.hint_dynamic();
-        self.link_or_cc_arg(format!("-l{name}"));
+        self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
     }
 
     fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
@@ -1668,7 +1668,7 @@ impl<'a> Linker for AixLinker<'a> {
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.link_or_cc_arg(format!("-l{name}"));
+            self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
         } else {
             let mut arg = OsString::from("-bkeepfile:");
             arg.push(find_native_static_library(name, verbatim, self.sess));
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c8bb229998e..87992ce2e11 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -6,6 +6,7 @@ use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::{fs, io, mem, str, thread};
 
+use rustc_abi::Size;
 use rustc_ast::attr;
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -355,6 +356,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub target_is_like_aix: bool,
     pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
     pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
+    pub pointer_size: Size,
 
     /// All commandline args used to invoke the compiler, with @file args fully expanded.
     /// This will only be used within debug info, e.g. in the pdb file on windows
@@ -1216,6 +1218,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         split_debuginfo: tcx.sess.split_debuginfo(),
         split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind,
         parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend,
+        pointer_size: tcx.data_layout.pointer_size,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 673740b4aab..90c53c34768 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -8,8 +8,6 @@ use rustc_ast::{MetaItem, MetaItemInner, attr};
 use rustc_attr_parsing::ReprAttr::ReprAlign;
 use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::codes::*;
-use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
@@ -236,13 +234,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     && let Some(fn_sig) = fn_sig()
                     && fn_sig.skip_binder().abi() != ExternAbi::Rust
                 {
-                    struct_span_code_err!(
-                        tcx.dcx(),
-                        attr.span(),
-                        E0737,
-                        "`#[track_caller]` requires Rust ABI"
-                    )
-                    .emit();
+                    tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() });
                 }
                 if is_closure
                     && !tcx.features().closure_track_caller()
@@ -263,13 +255,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     if s.as_str().contains('\0') {
                         // `#[export_name = ...]` will be converted to a null-terminated string,
                         // so it may not contain any null characters.
-                        struct_span_code_err!(
-                            tcx.dcx(),
-                            attr.span(),
-                            E0648,
-                            "`export_name` may not contain null characters"
-                        )
-                        .emit();
+                        tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() });
                     }
                     codegen_fn_attrs.export_name = Some(s);
                     mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
@@ -394,47 +380,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 [sym::arm, sym::a32 | sym::t32]
                                     if !tcx.sess.target.has_thumb_interworking =>
                                 {
-                                    struct_span_code_err!(
-                                        tcx.dcx(),
-                                        attr.span(),
-                                        E0779,
-                                        "target does not support `#[instruction_set]`"
-                                    )
-                                    .emit();
+                                    tcx.dcx().emit_err(errors::UnsuportedInstructionSet {
+                                        span: attr.span(),
+                                    });
                                     None
                                 }
                                 [sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
                                 [sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
                                 _ => {
-                                    struct_span_code_err!(
-                                        tcx.dcx(),
-                                        attr.span(),
-                                        E0779,
-                                        "invalid instruction set specified",
-                                    )
-                                    .emit();
+                                    tcx.dcx().emit_err(errors::InvalidInstructionSet {
+                                        span: attr.span(),
+                                    });
                                     None
                                 }
                             }
                         }
                         [] => {
-                            struct_span_code_err!(
-                                tcx.dcx(),
-                                attr.span(),
-                                E0778,
-                                "`#[instruction_set]` requires an argument"
-                            )
-                            .emit();
+                            tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
                             None
                         }
                         _ => {
-                            struct_span_code_err!(
-                                tcx.dcx(),
-                                attr.span(),
-                                E0779,
-                                "cannot specify more than one instruction set"
-                            )
-                            .emit();
+                            tcx.dcx()
+                                .emit_err(errors::MultipleInstructionSet { span: attr.span() });
                             None
                         }
                     })
@@ -445,58 +412,38 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     let mut entry = None;
                     for item in l {
                         let Some(meta_item) = item.meta_item() else {
-                            tcx.dcx().span_err(item.span(), "expected name value pair");
+                            tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
                             continue;
                         };
 
                         let Some(name_value_lit) = meta_item.name_value_literal() else {
-                            tcx.dcx().span_err(item.span(), "expected name value pair");
+                            tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
                             continue;
                         };
 
-                        fn emit_error_with_label(
-                            tcx: TyCtxt<'_>,
-                            span: Span,
-                            error: impl Into<DiagMessage>,
-                            label: impl Into<SubdiagMessage>,
-                        ) {
-                            let mut err: rustc_errors::Diag<'_, _> =
-                                tcx.dcx().struct_span_err(span, error);
-                            err.span_label(span, label);
-                            err.emit();
-                        }
-
                         let attrib_to_write = match meta_item.name_or_empty() {
                             sym::prefix_nops => &mut prefix,
                             sym::entry_nops => &mut entry,
                             _ => {
-                                emit_error_with_label(
-                                    tcx,
-                                    item.span(),
-                                    "unexpected parameter name",
-                                    format!("expected {} or {}", sym::prefix_nops, sym::entry_nops),
-                                );
+                                tcx.dcx().emit_err(errors::UnexpectedParameterName {
+                                    span: item.span(),
+                                    prefix_nops: sym::prefix_nops,
+                                    entry_nops: sym::entry_nops,
+                                });
                                 continue;
                             }
                         };
 
                         let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
-                            emit_error_with_label(
-                                tcx,
-                                name_value_lit.span,
-                                "invalid literal value",
-                                "value must be an integer between `0` and `255`",
-                            );
+                            tcx.dcx().emit_err(errors::InvalidLiteralValue {
+                                span: name_value_lit.span,
+                            });
                             continue;
                         };
 
                         let Ok(val) = val.get().try_into() else {
-                            emit_error_with_label(
-                                tcx,
-                                name_value_lit.span,
-                                "integer value out of range",
-                                "value must be between `0` and `255`",
-                            );
+                            tcx.dcx()
+                                .emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
                             continue;
                         };
 
@@ -533,7 +480,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         inline_span = Some(attr.span());
 
         let [item] = &items[..] else {
-            struct_span_code_err!(tcx.dcx(), attr.span(), E0534, "expected one argument").emit();
+            tcx.dcx().emit_err(errors::ExpectedOneArgument { span: attr.span() });
             return InlineAttr::None;
         };
 
@@ -542,9 +489,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         } else if item.has_name(sym::never) {
             InlineAttr::Never
         } else {
-            struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument")
-                .with_help("valid inline arguments are `always` and `never`")
-                .emit();
+            tcx.dcx().emit_err(errors::InvalidArgument { span: items[0].span() });
 
             InlineAttr::None
         }
@@ -575,9 +520,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         if !attr.has_name(sym::optimize) {
             return ia;
         }
-        let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit();
         if attr.is_word() {
-            err(attr.span(), "expected one argument");
+            tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
             return ia;
         }
         let Some(ref items) = attr.meta_item_list() else {
@@ -586,7 +530,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
         inline_span = Some(attr.span());
         let [item] = &items[..] else {
-            err(attr.span(), "expected one argument");
+            tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
             return OptimizeAttr::Default;
         };
         if item.has_name(sym::size) {
@@ -596,7 +540,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         } else if item.has_name(sym::none) {
             OptimizeAttr::DoNotOptimize
         } else {
-            err(item.span(), "invalid argument");
+            tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() });
             OptimizeAttr::Default
         }
     });
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index ccf6d12977f..394c80fcfbd 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -136,6 +136,110 @@ pub(crate) struct NoSavedObjectFile<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_requires_rust_abi, code = E0737)]
+pub(crate) struct RequiresRustAbi {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_null_on_export, code = E0648)]
+pub(crate) struct NullOnExport {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)]
+pub(crate) struct UnsuportedInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_instruction_set, code = E0779)]
+pub(crate) struct InvalidInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_bare_instruction_set, code = E0778)]
+pub(crate) struct BareInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_multiple_instruction_set, code = E0779)]
+pub(crate) struct MultipleInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_name_value_pair)]
+pub(crate) struct ExpectedNameValuePair {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unexpected_parameter_name)]
+pub(crate) struct UnexpectedParameterName {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub prefix_nops: Symbol,
+    pub entry_nops: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_literal_value)]
+pub(crate) struct InvalidLiteralValue {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_out_of_range_integer)]
+pub(crate) struct OutOfRangeInteger {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_one_argument, code = E0534)]
+pub(crate) struct ExpectedOneArgument {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_one_argument, code = E0722)]
+pub(crate) struct ExpectedOneArgumentOptimize {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_argument, code = E0535)]
+#[help]
+pub(crate) struct InvalidArgument {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_argument, code = E0722)]
+pub(crate) struct InvalidArgumentOptimize {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_copy_path_buf)]
 pub(crate) struct CopyPathBuf {
     pub source_file: PathBuf,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e2a9b540d30..6d1930a402d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -3,6 +3,7 @@ use std::cmp;
 use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange};
 use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::packed::Pu128;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
@@ -406,6 +407,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
                 bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect);
             }
+        } else if target_iter.len() == 2
+            && self.mir[targets.otherwise()].is_empty_unreachable()
+            && targets.all_values().contains(&Pu128(0))
+            && targets.all_values().contains(&Pu128(1))
+        {
+            // This is the really common case for `bool`, `Option`, etc.
+            // By using `trunc nuw` we communicate that other values are
+            // impossible without needing `switch` or `assume`s.
+            let true_bb = targets.target_for_value(1);
+            let false_bb = targets.target_for_value(0);
+            let true_ll = helper.llbb_with_cleanup(self, true_bb);
+            let false_ll = helper.llbb_with_cleanup(self, false_bb);
+
+            let expected_cond_value = if self.cx.sess().opts.optimize == OptLevel::No {
+                None
+            } else {
+                match (self.cold_blocks[true_bb], self.cold_blocks[false_bb]) {
+                    // Same coldness, no expectation
+                    (true, true) | (false, false) => None,
+                    // Different coldness, expect the non-cold one
+                    (true, false) => Some(false),
+                    (false, true) => Some(true),
+                }
+            };
+
+            let bool_ty = bx.tcx().types.bool;
+            let cond = if switch_ty == bool_ty {
+                discr_value
+            } else {
+                let bool_llty = bx.immediate_backend_type(bx.layout_of(bool_ty));
+                bx.unchecked_utrunc(discr_value, bool_llty)
+            };
+            bx.cond_br_with_expect(cond, true_ll, false_ll, expected_cond_value);
         } else if self.cx.sess().opts.optimize == OptLevel::No
             && target_iter.len() == 2
             && self.mir[targets.otherwise()].is_empty_unreachable()
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 00e01e47fee..6988724b421 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -133,7 +133,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         Self::alloca(bx, ptr_layout)
     }
 
-    pub fn len<Cx: ConstCodegenMethods<'tcx, Value = V>>(&self, cx: &Cx) -> V {
+    pub fn len<Cx: ConstCodegenMethods<Value = V>>(&self, cx: &Cx) -> V {
         if let FieldsShape::Array { count, .. } = self.layout.fields {
             if self.layout.is_unsized() {
                 assert_eq!(count, 0);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index ff555f4273c..95b108b1d33 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -364,6 +364,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> Bx::Value {
         assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
 
+        // While optimizations will remove no-op transmutes, they might still be
+        // there in debug or things that aren't no-op in MIR because they change
+        // the Rust type but not the underlying layout/niche.
+        if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
+            return imm;
+        }
+
         use abi::Primitive::*;
         imm = bx.from_immediate(imm);
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs
index 60d8f2a9ece..49c51caa996 100644
--- a/compiler/rustc_codegen_ssa/src/traits/abi.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs
@@ -1,5 +1,5 @@
 use super::BackendTypes;
 
-pub trait AbiBuilderMethods<'tcx>: BackendTypes {
+pub trait AbiBuilderMethods: BackendTypes {
     fn get_param(&mut self, index: usize) -> Self::Value;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 99fd6b6510f..5f91133d5b4 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -40,7 +40,7 @@ pub trait BuilderMethods<'a, 'tcx>:
     + CoverageInfoBuilderMethods<'tcx>
     + DebugInfoBuilderMethods
     + ArgAbiBuilderMethods<'tcx>
-    + AbiBuilderMethods<'tcx>
+    + AbiBuilderMethods
     + IntrinsicCallBuilderMethods<'tcx>
     + AsmBuilderMethods<'tcx>
     + StaticBuilderMethods
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index dc6b68ceff7..d83a04d814b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -3,7 +3,7 @@ use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
 
 use super::BackendTypes;
 
-pub trait ConstCodegenMethods<'tcx>: BackendTypes {
+pub trait ConstCodegenMethods: BackendTypes {
     // Constant constructors
     fn const_null(&self, t: Self::Type) -> Self::Value;
     /// Generate an uninitialized value (matching uninitialized memory in MIR).
@@ -37,7 +37,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes {
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
 
-    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value;
 
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 90fcfbe4da7..239857a4298 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -55,7 +55,7 @@ pub trait CodegenObject = Copy + PartialEq + fmt::Debug;
 pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
     + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
     + TypeCodegenMethods<'tcx>
-    + ConstCodegenMethods<'tcx>
+    + ConstCodegenMethods
     + StaticCodegenMethods
     + DebugInfoCodegenMethods<'tcx>
     + AsmCodegenMethods<'tcx>
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index fbd927d0d66..32d9f27d32d 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -9,7 +9,7 @@ use super::misc::MiscCodegenMethods;
 use crate::common::TypeKind;
 use crate::mir::place::PlaceRef;
 
-pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes {
+pub trait BaseTypeCodegenMethods: BackendTypes {
     fn type_i8(&self) -> Self::Type;
     fn type_i16(&self) -> Self::Type;
     fn type_i32(&self) -> Self::Type;
@@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes {
 }
 
 pub trait DerivedTypeCodegenMethods<'tcx>:
-    BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
+    BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
 {
     fn type_int(&self) -> Self::Type {
         match &self.sess().target.c_int_width[..] {
@@ -87,10 +87,7 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
 }
 
 impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where
-    Self: BaseTypeCodegenMethods<'tcx>
-        + MiscCodegenMethods<'tcx>
-        + HasTyCtxt<'tcx>
-        + HasTypingEnv<'tcx>
+    Self: BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
 {
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 43631330f89..e4b2fe5d153 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -104,7 +104,7 @@ fn intern_as_new_static<'tcx>(
 ) {
     let feed = tcx.create_def(
         static_id,
-        sym::nested,
+        Some(sym::nested),
         DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
     );
     tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs
index 0e5ecfd9bff..a636d09fcae 100644
--- a/compiler/rustc_data_structures/src/aligned.rs
+++ b/compiler/rustc_data_structures/src/aligned.rs
@@ -2,10 +2,8 @@ use std::ptr::Alignment;
 
 /// Returns the ABI-required minimum alignment of a type in bytes.
 ///
-/// This is equivalent to [`mem::align_of`], but also works for some unsized
+/// This is equivalent to [`align_of`], but also works for some unsized
 /// types (e.g. slices or rustc's `List`s).
-///
-/// [`mem::align_of`]: std::mem::align_of
 pub const fn align_of<T: ?Sized + Aligned>() -> Alignment {
     T::ALIGN
 }
@@ -15,10 +13,10 @@ pub const fn align_of<T: ?Sized + Aligned>() -> Alignment {
 /// # Safety
 ///
 /// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it
-/// is [`mem::align_of<Self>()`], for unsized types it depends on the type, for
+/// is [`align_of::<Self>()`], for unsized types it depends on the type, for
 /// example `[T]` has alignment of `T`.
 ///
-/// [`mem::align_of<Self>()`]: std::mem::align_of
+/// [`align_of::<Self>()`]: align_of
 pub unsafe trait Aligned {
     /// Alignment of `Self`.
     const ALIGN: Alignment;
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 39db551adfb..60f007083ba 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -863,15 +863,13 @@ fn get_thread_id() -> u32 {
 cfg_match! {
     windows => {
         pub fn get_resident_set_size() -> Option<usize> {
-            use std::mem;
-
             use windows::{
                 Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
                 Win32::System::Threading::GetCurrentProcess,
             };
 
             let mut pmc = PROCESS_MEMORY_COUNTERS::default();
-            let pmc_size = mem::size_of_val(&pmc);
+            let pmc_size = size_of_val(&pmc);
             unsafe {
                 K32GetProcessMemoryInfo(
                     GetCurrentProcess(),
@@ -889,7 +887,7 @@ cfg_match! {
         pub fn get_resident_set_size() -> Option<usize> {
             use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO};
             use std::mem;
-            const PROC_TASKINFO_SIZE: c_int = mem::size_of::<proc_taskinfo>() as c_int;
+            const PROC_TASKINFO_SIZE: c_int = size_of::<proc_taskinfo>() as c_int;
 
             unsafe {
                 let mut info: proc_taskinfo = mem::zeroed();
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index e6be9c256f0..3016348f224 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,7 +1,7 @@
 use std::borrow::Borrow;
 use std::collections::hash_map::RawEntryMut;
 use std::hash::{Hash, Hasher};
-use std::{iter, mem};
+use std::iter;
 
 use either::Either;
 
@@ -221,7 +221,7 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
 /// consistently for each `Sharded` instance.
 #[inline]
 fn get_shard_hash(hash: u64) -> usize {
-    let hash_len = mem::size_of::<usize>();
+    let hash_len = size_of::<usize>();
     // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
     // hashbrown also uses the lowest bits, so we can't use those
     (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 7fffeaddb86..9f4d2ea5c1a 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -490,7 +490,7 @@ pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
 // would be bad.
 impl<G> !Clone for Diag<'_, G> {}
 
-rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * std::mem::size_of::<usize>());
+rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>());
 
 impl<G: EmissionGuarantee> Deref for Diag<'_, G> {
     type Target = DiagInner;
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index f7f84239308..21255fcca96 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -113,24 +113,11 @@ impl Margin {
         self.computed_left > 0
     }
 
-    fn was_cut_right(&self, line_len: usize) -> bool {
-        let right =
-            if self.computed_right == self.span_right || self.computed_right == self.label_right {
-                // FIXME: This comment refers to the only callsite of this method.
-                //        Rephrase it or refactor it, so it can stand on its own.
-                // Account for the "..." padding given above. Otherwise we end up with code lines
-                // that do fit but end in "..." as if they were trimmed.
-                // FIXME: Don't hard-code this offset. Is this meant to represent
-                //        `2 * str_width(self.margin())`?
-                self.computed_right - 6
-            } else {
-                self.computed_right
-            };
-        right < line_len && self.computed_left + self.column_width < line_len
-    }
-
     fn compute(&mut self, max_line_len: usize) {
         // When there's a lot of whitespace (>20), we want to trim it as it is useless.
+        // FIXME: this doesn't account for '\t', but to do so correctly we need to perform that
+        // calculation later, right before printing in order to be accurate with both unicode
+        // handling and trimming of long lines.
         self.computed_left = if self.whitespace_left > 20 {
             self.whitespace_left - 16 // We want some padding.
         } else {
@@ -616,7 +603,6 @@ pub struct HumanEmitter {
     #[setters(skip)]
     fallback_bundle: LazyFallbackBundle,
     short_message: bool,
-    teach: bool,
     ui_testing: bool,
     ignored_directories_in_source_blocks: Vec<String>,
     diagnostic_width: Option<usize>,
@@ -642,7 +628,6 @@ impl HumanEmitter {
             fluent_bundle: None,
             fallback_bundle,
             short_message: false,
-            teach: false,
             ui_testing: false,
             ignored_directories_in_source_blocks: Vec::new(),
             diagnostic_width: None,
@@ -670,43 +655,43 @@ impl HumanEmitter {
         width_offset: usize,
         code_offset: usize,
         margin: Margin,
-    ) {
-        // Tabs are assumed to have been replaced by spaces in calling code.
-        debug_assert!(!source_string.contains('\t'));
+    ) -> usize {
         let line_len = source_string.len();
         // Create the source line we will highlight.
         let left = margin.left(line_len);
         let right = margin.right(line_len);
         // FIXME: The following code looks fishy. See #132860.
         // On long lines, we strip the source line, accounting for unicode.
-        let mut taken = 0;
         let code: String = source_string
             .chars()
-            .skip(left)
-            .take_while(|ch| {
-                // Make sure that the trimming on the right will fall within the terminal width.
-                let next = char_width(*ch);
-                if taken + next > right - left {
-                    return false;
-                }
-                taken += next;
-                true
-            })
+            .enumerate()
+            .skip_while(|(i, _)| *i < left)
+            .take_while(|(i, _)| *i < right)
+            .map(|(_, c)| c)
             .collect();
+        let code = normalize_whitespace(&code);
+        let was_cut_right =
+            source_string.chars().enumerate().skip_while(|(i, _)| *i < right).next().is_some();
         buffer.puts(line_offset, code_offset, &code, Style::Quotation);
         let placeholder = self.margin();
         if margin.was_cut_left() {
             // We have stripped some code/whitespace from the beginning, make it clear.
             buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber);
         }
-        if margin.was_cut_right(line_len) {
+        if was_cut_right {
             let padding = str_width(placeholder);
             // We have stripped some code after the rightmost span end, make it clear we did so.
-            buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber);
+            buffer.puts(
+                line_offset,
+                code_offset + str_width(&code) - padding,
+                placeholder,
+                Style::LineNumber,
+            );
         }
         buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
 
         self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
+        left
     }
 
     #[instrument(level = "trace", skip(self), ret)]
@@ -738,22 +723,16 @@ impl HumanEmitter {
             return Vec::new();
         }
 
-        let source_string = match file.get_line(line.line_index - 1) {
-            Some(s) => normalize_whitespace(&s),
-            None => return Vec::new(),
+        let Some(source_string) = file.get_line(line.line_index - 1) else {
+            return Vec::new();
         };
         trace!(?source_string);
 
         let line_offset = buffer.num_lines();
 
-        // Left trim
-        let left = margin.left(source_string.len());
-
+        // Left trim.
         // FIXME: This looks fishy. See #132860.
-        // Account for unicode characters of width !=0 that were removed.
-        let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum();
-
-        self.draw_line(
+        let left = self.draw_line(
             buffer,
             &source_string,
             line.line_index,
@@ -784,7 +763,7 @@ impl HumanEmitter {
         let mut short_start = true;
         for ann in &line.annotations {
             if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
-                if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) {
+                if source_string.chars().take(ann.start_col.file).all(|c| c.is_whitespace()) {
                     let uline = self.underline(ann.is_primary);
                     let chr = uline.multiline_whole_line;
                     annotations.push((depth, uline.style));
@@ -903,11 +882,16 @@ impl HumanEmitter {
         //      |      x_span
         //      <EMPTY LINE>
         //
+        let mut overlap = vec![false; annotations.len()];
         let mut annotations_position = vec![];
         let mut line_len: usize = 0;
         let mut p = 0;
         for (i, annotation) in annotations.iter().enumerate() {
             for (j, next) in annotations.iter().enumerate() {
+                if overlaps(next, annotation, 0) && j > i {
+                    overlap[i] = true;
+                    overlap[j] = true;
+                }
                 if overlaps(next, annotation, 0)  // This label overlaps with another one and both
                     && annotation.has_label()     // take space (they have text and are not
                     && j > i                      // multiline lines).
@@ -1035,24 +1019,21 @@ impl HumanEmitter {
             let pos = pos + 1;
             match annotation.annotation_type {
                 AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => {
+                    let pre: usize = source_string
+                        .chars()
+                        .take(annotation.start_col.file)
+                        .skip(left)
+                        .map(|c| char_width(c))
+                        .sum();
                     self.draw_range(
                         buffer,
                         underline.multiline_horizontal,
                         line_offset + pos,
                         width_offset + depth,
-                        (code_offset + annotation.start_col.display).saturating_sub(left),
+                        code_offset + pre,
                         underline.style,
                     );
                 }
-                _ if self.teach => {
-                    buffer.set_style_range(
-                        line_offset,
-                        (code_offset + annotation.start_col.display).saturating_sub(left),
-                        (code_offset + annotation.end_col.display).saturating_sub(left),
-                        underline.style,
-                        annotation.is_primary,
-                    );
-                }
                 _ => {}
             }
         }
@@ -1072,11 +1053,18 @@ impl HumanEmitter {
             let underline = self.underline(annotation.is_primary);
             let pos = pos + 1;
 
+            let code_offset = code_offset
+                + source_string
+                    .chars()
+                    .take(annotation.start_col.file)
+                    .skip(left)
+                    .map(|c| char_width(c))
+                    .sum::<usize>();
             if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
                 for p in line_offset + 1..=line_offset + pos {
                     buffer.putc(
                         p,
-                        (code_offset + annotation.start_col.display).saturating_sub(left),
+                        code_offset,
                         match annotation.annotation_type {
                             AnnotationType::MultilineLine(_) => underline.multiline_vertical,
                             _ => underline.vertical_text_line,
@@ -1087,7 +1075,7 @@ impl HumanEmitter {
                 if let AnnotationType::MultilineStart(_) = annotation.annotation_type {
                     buffer.putc(
                         line_offset + pos,
-                        (code_offset + annotation.start_col.display).saturating_sub(left),
+                        code_offset,
                         underline.bottom_right,
                         underline.style,
                     );
@@ -1097,7 +1085,7 @@ impl HumanEmitter {
                 {
                     buffer.putc(
                         line_offset + pos,
-                        (code_offset + annotation.start_col.display).saturating_sub(left),
+                        code_offset,
                         underline.multiline_bottom_right_with_text,
                         underline.style,
                     );
@@ -1155,13 +1143,30 @@ impl HumanEmitter {
             let style =
                 if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary };
             let (pos, col) = if pos == 0 {
-                if annotation.end_col.display == 0 {
-                    (pos + 1, (annotation.end_col.display + 2).saturating_sub(left))
+                let pre: usize = source_string
+                    .chars()
+                    .take(annotation.end_col.file)
+                    .skip(left)
+                    .map(|c| char_width(c))
+                    .sum();
+                if annotation.end_col.file == 0 {
+                    (pos + 1, (pre + 2))
                 } else {
-                    (pos + 1, (annotation.end_col.display + 1).saturating_sub(left))
+                    let pad = if annotation.end_col.file - annotation.start_col.file == 0 {
+                        2
+                    } else {
+                        1
+                    };
+                    (pos + 1, (pre + pad))
                 }
             } else {
-                (pos + 2, annotation.start_col.display.saturating_sub(left))
+                let pre: usize = source_string
+                    .chars()
+                    .take(annotation.start_col.file)
+                    .skip(left)
+                    .map(|c| char_width(c))
+                    .sum();
+                (pos + 2, pre)
             };
             if let Some(ref label) = annotation.label {
                 buffer.puts(line_offset + pos, code_offset + col, label, style);
@@ -1194,14 +1199,35 @@ impl HumanEmitter {
         //   |  _^  test
         for &(pos, annotation) in &annotations_position {
             let uline = self.underline(annotation.is_primary);
-            for p in annotation.start_col.display..annotation.end_col.display {
+            let width = annotation.end_col.file - annotation.start_col.file;
+            let previous: String =
+                source_string.chars().take(annotation.start_col.file).skip(left).collect();
+            let underlined: String =
+                source_string.chars().skip(annotation.start_col.file).take(width).collect();
+            debug!(?previous, ?underlined);
+            let code_offset = code_offset
+                + source_string
+                    .chars()
+                    .take(annotation.start_col.file)
+                    .skip(left)
+                    .map(|c| char_width(c))
+                    .sum::<usize>();
+            let ann_width: usize = source_string
+                .chars()
+                .skip(annotation.start_col.file)
+                .take(width)
+                .map(|c| char_width(c))
+                .sum();
+            let ann_width = if ann_width == 0
+                && matches!(annotation.annotation_type, AnnotationType::Singleline)
+            {
+                1
+            } else {
+                ann_width
+            };
+            for p in 0..ann_width {
                 // The default span label underline.
-                buffer.putc(
-                    line_offset + 1,
-                    (code_offset + p).saturating_sub(left),
-                    uline.underline,
-                    uline.style,
-                );
+                buffer.putc(line_offset + 1, code_offset + p, uline.underline, uline.style);
             }
 
             if pos == 0
@@ -1213,7 +1239,7 @@ impl HumanEmitter {
                 // The beginning of a multiline span with its leftward moving line on the same line.
                 buffer.putc(
                     line_offset + 1,
-                    (code_offset + annotation.start_col.display).saturating_sub(left),
+                    code_offset,
                     match annotation.annotation_type {
                         AnnotationType::MultilineStart(_) => uline.top_right_flat,
                         AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line,
@@ -1231,7 +1257,7 @@ impl HumanEmitter {
                 // so we start going down first.
                 buffer.putc(
                     line_offset + 1,
-                    (code_offset + annotation.start_col.display).saturating_sub(left),
+                    code_offset,
                     match annotation.annotation_type {
                         AnnotationType::MultilineStart(_) => uline.multiline_start_down,
                         AnnotationType::MultilineEnd(_) => uline.multiline_end_up,
@@ -1241,11 +1267,37 @@ impl HumanEmitter {
                 );
             } else if pos != 0 && annotation.has_label() {
                 // The beginning of a span label with an actual label, we'll point down.
-                buffer.putc(
+                buffer.putc(line_offset + 1, code_offset, uline.label_start, uline.style);
+            }
+        }
+
+        // We look for individual *long* spans, and we trim the *middle*, so that we render
+        // LL | ...= [0, 0, 0, ..., 0, 0];
+        //    |      ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]`
+        for (i, (_pos, annotation)) in annotations_position.iter().enumerate() {
+            // Skip cases where multiple spans overlap each other.
+            if overlap[i] {
+                continue;
+            };
+            let AnnotationType::Singleline = annotation.annotation_type else { continue };
+            let width = annotation.end_col.display - annotation.start_col.display;
+            if width > margin.column_width * 2 && width > 10 {
+                // If the terminal is *too* small, we keep at least a tiny bit of the span for
+                // display.
+                let pad = max(margin.column_width / 3, 5);
+                // Code line
+                buffer.replace(
+                    line_offset,
+                    annotation.start_col.file + pad,
+                    annotation.end_col.file - pad,
+                    self.margin(),
+                );
+                // Underline line
+                buffer.replace(
                     line_offset + 1,
-                    (code_offset + annotation.start_col.display).saturating_sub(left),
-                    uline.label_start,
-                    uline.style,
+                    annotation.start_col.file + pad,
+                    annotation.end_col.file - pad,
+                    self.margin(),
                 );
             }
         }
@@ -1702,17 +1754,11 @@ impl HumanEmitter {
                         // non-rustc_lexer::is_whitespace() chars are reported as an
                         // error (ex. no-break-spaces \u{a0}), and thus can't be considered
                         // for removal during error reporting.
+                        // FIXME: doesn't account for '\t' properly.
                         let leading_whitespace = source_string
                             .chars()
                             .take_while(|c| rustc_lexer::is_whitespace(*c))
-                            .map(|c| {
-                                match c {
-                                    // Tabs are displayed as 4 spaces
-                                    '\t' => 4,
-                                    _ => 1,
-                                }
-                            })
-                            .sum();
+                            .count();
                         if source_string.chars().any(|c| !rustc_lexer::is_whitespace(c)) {
                             whitespace_margin = min(whitespace_margin, leading_whitespace);
                         }
@@ -1726,8 +1772,8 @@ impl HumanEmitter {
                 let mut span_left_margin = usize::MAX;
                 for line in &annotated_file.lines {
                     for ann in &line.annotations {
-                        span_left_margin = min(span_left_margin, ann.start_col.display);
-                        span_left_margin = min(span_left_margin, ann.end_col.display);
+                        span_left_margin = min(span_left_margin, ann.start_col.file);
+                        span_left_margin = min(span_left_margin, ann.end_col.file);
                     }
                 }
                 if span_left_margin == usize::MAX {
@@ -1747,12 +1793,12 @@ impl HumanEmitter {
                             .map_or(0, |s| s.len()),
                     );
                     for ann in &line.annotations {
-                        span_right_margin = max(span_right_margin, ann.start_col.display);
-                        span_right_margin = max(span_right_margin, ann.end_col.display);
+                        span_right_margin = max(span_right_margin, ann.start_col.file);
+                        span_right_margin = max(span_right_margin, ann.end_col.file);
                         // FIXME: account for labels not in the same line
                         let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1);
                         label_right_margin =
-                            max(label_right_margin, ann.end_col.display + label_right);
+                            max(label_right_margin, ann.end_col.file + label_right);
                     }
                 }
 
@@ -1763,15 +1809,7 @@ impl HumanEmitter {
                     width_offset + annotated_file.multiline_depth + 1
                 };
 
-                let column_width = if let Some(width) = self.diagnostic_width {
-                    width.saturating_sub(code_offset)
-                } else if self.ui_testing || cfg!(miri) {
-                    DEFAULT_COLUMN_WIDTH
-                } else {
-                    termize::dimensions()
-                        .map(|(w, _)| w.saturating_sub(code_offset))
-                        .unwrap_or(DEFAULT_COLUMN_WIDTH)
-                };
+                let column_width = self.column_width(code_offset);
 
                 let margin = Margin::new(
                     whitespace_margin,
@@ -1928,6 +1966,18 @@ impl HumanEmitter {
         Ok(())
     }
 
+    fn column_width(&self, code_offset: usize) -> usize {
+        if let Some(width) = self.diagnostic_width {
+            width.saturating_sub(code_offset)
+        } else if self.ui_testing || cfg!(miri) {
+            DEFAULT_COLUMN_WIDTH
+        } else {
+            termize::dimensions()
+                .map(|(w, _)| w.saturating_sub(code_offset))
+                .unwrap_or(DEFAULT_COLUMN_WIDTH)
+        }
+    }
+
     fn emit_suggestion_default(
         &mut self,
         span: &MultiSpan,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index f69e756a3e1..86959b28e53 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -14,6 +14,7 @@
 #![feature(associated_type_defaults)]
 #![feature(box_into_inner)]
 #![feature(box_patterns)]
+#![feature(default_field_values)]
 #![feature(error_reporter)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs
index 7a991a2ace7..f02387d8335 100644
--- a/compiler/rustc_errors/src/markdown/parse.rs
+++ b/compiler/rustc_errors/src/markdown/parse.rs
@@ -40,11 +40,13 @@ type ParseResult<'a> = Option<Parsed<'a>>;
 
 /// Parsing context
 #[derive(Clone, Copy, Debug, PartialEq)]
+// The default values are the most common setting for non top-level parsing: not top block, not at
+// line start (yes leading whitespace, not escaped).
 struct Context {
     /// If true, we are at a the topmost level (not recursing a nested tt)
-    top_block: bool,
+    top_block: bool = false,
     /// Previous character
-    prev: Prev,
+    prev: Prev = Prev::Whitespace,
 }
 
 /// Character class preceding this one
@@ -57,14 +59,6 @@ enum Prev {
     Any,
 }
 
-impl Default for Context {
-    /// Most common setting for non top-level parsing: not top block, not at
-    /// line start (yes leading whitespace, not escaped)
-    fn default() -> Self {
-        Self { top_block: false, prev: Prev::Whitespace }
-    }
-}
-
 /// Flags to simple parser function
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum ParseOpt {
@@ -248,7 +242,7 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> {
     }
 
     let (txt, rest) = parse_to_newline(&buf[1..]);
-    let ctx = Context { top_block: false, prev: Prev::Whitespace };
+    let ctx = Context { .. };
     let stream = parse_recursive(txt, ctx);
 
     Some((MdTree::Heading(level.try_into().unwrap(), stream), rest))
@@ -257,7 +251,7 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> {
 /// Bulleted list
 fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> {
     let (txt, rest) = get_indented_section(&buf[2..]);
-    let ctx = Context { top_block: false, prev: Prev::Whitespace };
+    let ctx = Context { .. };
     let stream = parse_recursive(trim_ascii_start(txt), ctx);
     (MdTree::UnorderedListItem(stream), rest)
 }
@@ -266,7 +260,7 @@ fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> {
 fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> {
     let (num, pos) = ord_list_start(buf).unwrap(); // success tested in caller
     let (txt, rest) = get_indented_section(&buf[pos..]);
-    let ctx = Context { top_block: false, prev: Prev::Whitespace };
+    let ctx = Context { .. };
     let stream = parse_recursive(trim_ascii_start(txt), ctx);
     (MdTree::OrderedListItem(num, stream), rest)
 }
diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs
index 5ca9e9b18f3..790efd0286e 100644
--- a/compiler/rustc_errors/src/styled_buffer.rs
+++ b/compiler/rustc_errors/src/styled_buffer.rs
@@ -89,6 +89,19 @@ impl StyledBuffer {
         }
     }
 
+    pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) {
+        if start == end {
+            return;
+        }
+        if start > self.lines[line].len() || end > self.lines[line].len() {
+            return;
+        }
+        let _ = self.lines[line].drain(start..(end - string.chars().count()));
+        for (i, c) in string.chars().enumerate() {
+            self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber);
+        }
+    }
+
     /// For given `line` inserts `string` with `style` before old content of that line,
     /// adding lines if needed
     pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) {
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index b39ad8875a4..7741f6668c3 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -1,6 +1,7 @@
 //! List of the unstable feature gates.
 
 use std::path::PathBuf;
+use std::time::{SystemTime, UNIX_EPOCH};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::{Span, Symbol, sym};
@@ -473,6 +474,8 @@ declare_features! (
     (unstable, doc_masked, "1.21.0", Some(44027)),
     /// Allows `dyn* Trait` objects.
     (incomplete, dyn_star, "1.65.0", Some(102425)),
+    /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
+    (incomplete, ergonomic_clones, "CURRENT_RUSTC_VERSION", Some(132290)),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
     (unstable, exhaustive_patterns, "1.13.0", Some(51085)),
     /// Allows explicit tail calls via `become` expression.
@@ -669,6 +672,7 @@ declare_features! (
     (unstable, xop_target_feature, "1.81.0", Some(127208)),
     /// Allows `do yeet` expressions
     (unstable, yeet_expr, "1.62.0", Some(96373)),
+    (unstable, yield_expr, "CURRENT_RUSTC_VERSION", Some(43122)),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
@@ -685,11 +689,13 @@ impl Features {
     ) -> Result<(), Box<dyn std::error::Error>> {
         #[derive(serde::Serialize)]
         struct LibFeature {
+            timestamp: u128,
             symbol: String,
         }
 
         #[derive(serde::Serialize)]
         struct LangFeature {
+            timestamp: u128,
             symbol: String,
             since: Option<String>,
         }
@@ -703,10 +709,20 @@ impl Features {
         let metrics_file = std::fs::File::create(metrics_path)?;
         let metrics_file = std::io::BufWriter::new(metrics_file);
 
+        let now = || {
+            SystemTime::now()
+                .duration_since(UNIX_EPOCH)
+                .expect("system time should always be greater than the unix epoch")
+                .as_nanos()
+        };
+
         let lib_features = self
             .enabled_lib_features
             .iter()
-            .map(|EnabledLibFeature { gate_name, .. }| LibFeature { symbol: gate_name.to_string() })
+            .map(|EnabledLibFeature { gate_name, .. }| LibFeature {
+                symbol: gate_name.to_string(),
+                timestamp: now(),
+            })
             .collect();
 
         let lang_features = self
@@ -715,6 +731,7 @@ impl Features {
             .map(|EnabledLangFeature { gate_name, stable_since, .. }| LangFeature {
                 symbol: gate_name.to_string(),
                 since: stable_since.map(|since| since.to_string()),
+                timestamp: now(),
             })
             .collect();
 
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 7e3a8561da0..5f8941d4754 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -253,7 +253,9 @@ impl DefKind {
         }
     }
 
-    pub fn def_path_data(self, name: Symbol) -> DefPathData {
+    // Some `DefKind`s require a name, some don't. Panics if one is needed but
+    // not provided. (`AssocTy` is an exception, see below.)
+    pub fn def_path_data(self, name: Option<Symbol>) -> DefPathData {
         match self {
             DefKind::Mod
             | DefKind::Struct
@@ -264,9 +266,13 @@ impl DefKind {
             | DefKind::TyAlias
             | DefKind::ForeignTy
             | DefKind::TraitAlias
-            | DefKind::AssocTy
             | DefKind::TyParam
-            | DefKind::ExternCrate => DefPathData::TypeNs(name),
+            | DefKind::ExternCrate => DefPathData::TypeNs(Some(name.unwrap())),
+
+            // An associated type names will be missing for an RPITIT. It will
+            // later be given a name with `synthetic` in it, if necessary.
+            DefKind::AssocTy => DefPathData::TypeNs(name),
+
             // It's not exactly an anon const, but wrt DefPathData, there
             // is no difference.
             DefKind::Static { nested: true, .. } => DefPathData::AnonConst,
@@ -276,9 +282,9 @@ impl DefKind {
             | DefKind::Static { .. }
             | DefKind::AssocFn
             | DefKind::AssocConst
-            | DefKind::Field => DefPathData::ValueNs(name),
-            DefKind::Macro(..) => DefPathData::MacroNs(name),
-            DefKind::LifetimeParam => DefPathData::LifetimeNs(name),
+            | DefKind::Field => DefPathData::ValueNs(name.unwrap()),
+            DefKind::Macro(..) => DefPathData::MacroNs(name.unwrap()),
+            DefKind::LifetimeParam => DefPathData::LifetimeNs(name.unwrap()),
             DefKind::Ctor(..) => DefPathData::Ctor,
             DefKind::Use => DefPathData::Use,
             DefKind::ForeignMod => DefPathData::ForeignMod,
@@ -429,7 +435,7 @@ pub enum Res<Id = hir::HirId> {
         /// mention any generic parameters to allow the following with `min_const_generics`:
         /// ```
         /// # struct Foo;
-        /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
+        /// impl Foo { fn test() -> [u8; size_of::<Self>()] { todo!() } }
         ///
         /// struct Bar([u8; baz::<Self>()]);
         /// const fn baz<T>() -> usize { 10 }
@@ -439,7 +445,7 @@ pub enum Res<Id = hir::HirId> {
         /// compat lint:
         /// ```
         /// fn foo<T>() {
-        ///     let _bar = [1_u8; std::mem::size_of::<*mut T>()];
+        ///     let _bar = [1_u8; size_of::<*mut T>()];
         /// }
         /// ```
         // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index c4c309e77e1..61f5efd9978 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -271,8 +271,9 @@ pub enum DefPathData {
     Use,
     /// A global asm item.
     GlobalAsm,
-    /// Something in the type namespace.
-    TypeNs(Symbol),
+    /// Something in the type namespace. Will be empty for RPITIT associated
+    /// types, which are given a synthetic name later, if necessary.
+    TypeNs(Option<Symbol>),
     /// Something in the value namespace.
     ValueNs(Symbol),
     /// Something in the macro namespace.
@@ -410,8 +411,9 @@ impl DefPathData {
     pub fn get_opt_name(&self) -> Option<Symbol> {
         use self::DefPathData::*;
         match *self {
-            TypeNs(name) if name == kw::Empty => None,
-            TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
+            TypeNs(name) => name,
+
+            ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
 
             Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
             | OpaqueTy => None,
@@ -421,12 +423,14 @@ impl DefPathData {
     pub fn name(&self) -> DefPathDataName {
         use self::DefPathData::*;
         match *self {
-            TypeNs(name) if name == kw::Empty => {
-                DefPathDataName::Anon { namespace: sym::synthetic }
-            }
-            TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => {
-                DefPathDataName::Named(name)
+            TypeNs(name) => {
+                if let Some(name) = name {
+                    DefPathDataName::Named(name)
+                } else {
+                    DefPathDataName::Anon { namespace: sym::synthetic }
+                }
             }
+            ValueNs(name) | MacroNs(name) | LifetimeNs(name) => DefPathDataName::Named(name),
             // Note that this does not show up in user print-outs.
             CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
             Impl => DefPathDataName::Anon { namespace: kw::Impl },
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index df305e6e769..928455ace85 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2166,6 +2166,7 @@ impl Expr<'_> {
             | ExprKind::Tup(_)
             | ExprKind::Type(..)
             | ExprKind::UnsafeBinderCast(..)
+            | ExprKind::Use(..)
             | ExprKind::Err(_) => ExprPrecedence::Unambiguous,
 
             ExprKind::DropTemps(expr, ..) => expr.precedence(),
@@ -2212,6 +2213,7 @@ impl Expr<'_> {
             ExprKind::Path(QPath::TypeRelative(..))
             | ExprKind::Call(..)
             | ExprKind::MethodCall(..)
+            | ExprKind::Use(..)
             | ExprKind::Struct(..)
             | ExprKind::Tup(..)
             | ExprKind::If(..)
@@ -2285,7 +2287,9 @@ impl Expr<'_> {
 
     pub fn can_have_side_effects(&self) -> bool {
         match self.peel_drop_temps().kind {
-            ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false,
+            ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) | ExprKind::Use(..) => {
+                false
+            }
             ExprKind::Type(base, _)
             | ExprKind::Unary(_, base)
             | ExprKind::Field(base, _)
@@ -2547,6 +2551,8 @@ pub enum ExprKind<'hir> {
     ///
     /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
     MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
+    /// An use expression (e.g., `var.use`).
+    Use(&'hir Expr<'hir>, Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(&'hir [Expr<'hir>]),
     /// A binary operation (e.g., `a + b`, `a * b`).
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 41eb5b45bd1..3ef645a5f61 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -316,8 +316,8 @@ pub trait Visitor<'v>: Sized {
     fn visit_ident(&mut self, ident: Ident) -> Self::Result {
         walk_ident(self, ident)
     }
-    fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) -> Self::Result {
-        walk_mod(self, m, n)
+    fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result {
+        walk_mod(self, m)
     }
     fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result {
         walk_foreign_item(self, i)
@@ -363,7 +363,7 @@ pub trait Visitor<'v>: Sized {
     /// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
     /// ambiguous.
     ///
-    /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
+    /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
     fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
         walk_ty(self, t)
     }
@@ -374,7 +374,7 @@ pub trait Visitor<'v>: Sized {
     /// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
     /// ambiguous.
     ///
-    /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
+    /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
     fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
         walk_ambig_const_arg(self, c)
     }
@@ -464,8 +464,8 @@ pub trait Visitor<'v>: Sized {
     fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) -> Self::Result {
-        walk_enum_def(self, enum_definition, item_id)
+    fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result {
+        walk_enum_def(self, enum_definition)
     }
     fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result {
         walk_variant(self, v)
@@ -532,28 +532,25 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) ->
 }
 
 pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
+    try_visit!(visitor.visit_id(item.hir_id()));
     try_visit!(visitor.visit_ident(item.ident));
     match item.kind {
         ItemKind::ExternCrate(orig_name) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             visit_opt!(visitor, visit_name, orig_name);
         }
         ItemKind::Use(ref path, _) => {
             try_visit!(visitor.visit_use(path, item.hir_id()));
         }
         ItemKind::Static(ref typ, _, body) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_ty_unambig(typ));
             try_visit!(visitor.visit_nested_body(body));
         }
         ItemKind::Const(ref typ, ref generics, body) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_ty_unambig(typ));
             try_visit!(visitor.visit_generics(generics));
             try_visit!(visitor.visit_nested_body(body));
         }
         ItemKind::Fn { sig, generics, body: body_id, .. } => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_fn(
                 FnKind::ItemFn(item.ident, generics, sig.header),
                 sig.decl,
@@ -562,19 +559,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
                 item.owner_id.def_id,
             ));
         }
-        ItemKind::Macro(..) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
-        }
+        ItemKind::Macro(..) => {}
         ItemKind::Mod(ref module) => {
-            // `visit_mod()` takes care of visiting the `Item`'s `HirId`.
             try_visit!(visitor.visit_mod(module, item.span, item.hir_id()));
         }
         ItemKind::ForeignMod { abi: _, items } => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             walk_list!(visitor, visit_foreign_item_ref, items);
         }
         ItemKind::GlobalAsm { asm: _, fake_body } => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             // Visit the fake body, which contains the asm statement.
             // Therefore we should not visit the asm statement again
             // outside of the body, or some visitors won't have their
@@ -582,14 +574,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_nested_body(fake_body));
         }
         ItemKind::TyAlias(ref ty, ref generics) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_ty_unambig(ty));
             try_visit!(visitor.visit_generics(generics));
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             try_visit!(visitor.visit_generics(generics));
-            // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
-            try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id()));
+            try_visit!(visitor.visit_enum_def(enum_definition));
         }
         ItemKind::Impl(Impl {
             constness: _,
@@ -602,7 +592,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             self_ty,
             items,
         }) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             visit_opt!(visitor, visit_trait_ref, of_trait);
             try_visit!(visitor.visit_ty_unambig(self_ty));
@@ -611,17 +600,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
         ItemKind::Struct(ref struct_definition, ref generics)
         | ItemKind::Union(ref struct_definition, ref generics) => {
             try_visit!(visitor.visit_generics(generics));
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_variant_data(struct_definition));
         }
         ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
         }
         ItemKind::TraitAlias(ref generics, bounds) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             walk_list!(visitor, visit_param_bound, bounds);
         }
@@ -638,12 +624,7 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul
     visitor.visit_name(ident.name)
 }
 
-pub fn walk_mod<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    module: &'v Mod<'v>,
-    mod_hir_id: HirId,
-) -> V::Result {
-    try_visit!(visitor.visit_id(mod_hir_id));
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result {
     walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied());
     V::Result::output()
 }
@@ -821,6 +802,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             try_visit!(visitor.visit_expr(receiver));
             walk_list!(visitor, visit_expr, arguments);
         }
+        ExprKind::Use(expr, _) => {
+            try_visit!(visitor.visit_expr(expr));
+        }
         ExprKind::Binary(_, ref left_expression, ref right_expression) => {
             try_visit!(visitor.visit_expr(left_expression));
             try_visit!(visitor.visit_expr(right_expression));
@@ -1145,7 +1129,6 @@ pub fn walk_use<'v, V: Visitor<'v>>(
     path: &'v UsePath<'v>,
     hir_id: HirId,
 ) -> V::Result {
-    try_visit!(visitor.visit_id(hir_id));
     let UsePath { segments, ref res, span } = *path;
     for &res in res {
         try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id));
@@ -1326,9 +1309,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>(
 pub fn walk_enum_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     enum_definition: &'v EnumDef<'v>,
-    item_id: HirId,
 ) -> V::Result {
-    try_visit!(visitor.visit_id(item_id));
     walk_list!(visitor, visit_variant, enum_definition.variants);
     V::Result::output()
 }
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index c3b14a4e06c..29f4d5b8076 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -171,6 +171,7 @@ language_item_table! {
     Copy,                    sym::copy,                copy_trait,                 Target::Trait,          GenericRequirement::Exact(0);
     Clone,                   sym::clone,               clone_trait,                Target::Trait,          GenericRequirement::None;
     CloneFn,                 sym::clone_fn,            clone_fn,                   Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    UseCloned,               sym::use_cloned,          use_cloned_trait,           Target::Trait,          GenericRequirement::None;
     Sync,                    sym::sync,                sync_trait,                 Target::Trait,          GenericRequirement::Exact(0);
     DiscriminantKind,        sym::discriminant_kind,   discriminant_kind_trait,    Target::Trait,          GenericRequirement::None;
     /// The associated item of the `DiscriminantKind` trait.
diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs
index ba5b61d3fce..8a841a11556 100644
--- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs
+++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs
@@ -124,7 +124,10 @@ pub(crate) fn check_negative_auto_trait_impl<'tcx>(
                 // be implemented here to handle non-ADT rigid types.
                 Ok(())
             } else {
-                span_bug!(tcx.def_span(impl_def_id), "incoherent impl of negative auto trait");
+                Err(tcx.dcx().span_delayed_bug(
+                    tcx.def_span(impl_def_id),
+                    "incoherent impl of negative auto trait",
+                ))
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 590ade516ec..d63165f0f16 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -3,8 +3,11 @@ use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
+use rustc_middle::ty::{
+    self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, TypeckResults, UintTy,
+};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Symbol, sym};
@@ -14,12 +17,11 @@ use rustc_target::asm::{
 
 use crate::errors::RegisterTypeUnstable;
 
-pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'tcx>,
+pub struct InlineAsmCtxt<'a, 'tcx> {
     typing_env: ty::TypingEnv<'tcx>,
     target_features: &'tcx FxIndexSet<Symbol>,
-    expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
-    node_ty: Box<dyn Fn(hir::HirId) -> Ty<'tcx> + 'a>,
+    infcx: &'a InferCtxt<'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
 }
 
 enum NonAsmTypeReason<'tcx> {
@@ -31,34 +33,38 @@ enum NonAsmTypeReason<'tcx> {
 
 impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     pub fn new(
-        tcx: TyCtxt<'tcx>,
         def_id: LocalDefId,
+        infcx: &'a InferCtxt<'tcx>,
         typing_env: ty::TypingEnv<'tcx>,
-        expr_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
-        node_ty: impl Fn(hir::HirId) -> Ty<'tcx> + 'a,
+        typeck_results: &'a TypeckResults<'tcx>,
     ) -> Self {
         InlineAsmCtxt {
-            tcx,
             typing_env,
-            target_features: tcx.asm_target_features(def_id),
-            expr_ty: Box::new(expr_ty),
-            node_ty: Box::new(node_ty),
+            target_features: infcx.tcx.asm_target_features(def_id),
+            infcx,
+            typeck_results,
         }
     }
 
-    fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
-        (self.expr_ty)(expr)
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
     }
 
-    fn node_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
-        (self.node_ty)(hir_id)
+    fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
+        let ty = self.typeck_results.expr_ty_adjusted(expr);
+        let ty = self.infcx.resolve_vars_if_possible(ty);
+        if ty.has_non_region_infer() {
+            Ty::new_misc_error(self.tcx())
+        } else {
+            self.tcx().erase_regions(ty)
+        }
     }
 
     // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
     fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
         // Type still may have region variables, but `Sized` does not depend
         // on those, so just erase them before querying.
-        if ty.is_sized(self.tcx, self.typing_env) {
+        if ty.is_sized(self.tcx(), self.typing_env) {
             return true;
         }
         if let ty::Foreign(..) = ty.kind() {
@@ -68,7 +74,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     }
 
     fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
-        let asm_ty_isize = match self.tcx.sess.target.pointer_width {
+        let asm_ty_isize = match self.tcx().sess.target.pointer_width {
             16 => InlineAsmType::I16,
             32 => InlineAsmType::I32,
             64 => InlineAsmType::I64,
@@ -97,12 +103,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             ty::Adt(adt, args) if adt.repr().simd() => {
                 let fields = &adt.non_enum_variant().fields;
                 let field = &fields[FieldIdx::ZERO];
-                let elem_ty = field.ty(self.tcx, args);
+                let elem_ty = field.ty(self.tcx(), args);
 
                 let (size, ty) = match elem_ty.kind() {
                     ty::Array(ty, len) => {
-                        let len = self.tcx.normalize_erasing_regions(self.typing_env, *len);
-                        if let Some(len) = len.try_to_target_usize(self.tcx) {
+                        let len = self.tcx().normalize_erasing_regions(self.typing_env, *len);
+                        if let Some(len) = len.try_to_target_usize(self.tcx()) {
                             (len, *ty)
                         } else {
                             return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
@@ -122,7 +128,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         Ok(InlineAsmType::VecI128(size))
                     }
                     ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => {
-                        Ok(match self.tcx.sess.target.pointer_width {
+                        Ok(match self.tcx().sess.target.pointer_width {
                             16 => InlineAsmType::VecI16(size),
                             32 => InlineAsmType::VecI32(size),
                             64 => InlineAsmType::VecI64(size),
@@ -159,9 +165,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             // `!` is allowed for input but not for output (issue #87802)
             ty::Never if is_input => return None,
             _ if ty.references_error() => return None,
-            ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => {
+            ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => {
                 let fields = &adt.non_enum_variant().fields;
-                let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args);
+                let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx(), args);
                 // FIXME: Are we just trying to map to the `T` in `MaybeUninit<T>`?
                 // If so, just get it from the args.
                 let ty::Adt(ty, args) = ty.kind() else {
@@ -172,7 +178,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     "expected first field of `MaybeUninit` to be `ManuallyDrop`"
                 );
                 let fields = &ty.non_enum_variant().fields;
-                let ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
+                let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args);
                 self.get_asm_ty(ty)
             }
             _ => self.get_asm_ty(ty),
@@ -183,9 +189,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                 match reason {
                     NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => {
                         let msg = format!("cannot evaluate SIMD vector length `{len}`");
-                        self.tcx
+                        self.infcx
                             .dcx()
-                            .struct_span_err(self.tcx.def_span(did), msg)
+                            .struct_span_err(self.tcx().def_span(did), msg)
                             .with_span_note(
                                 expr.span,
                                 "SIMD vector length needs to be known statically for use in `asm!`",
@@ -194,7 +200,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     }
                     NonAsmTypeReason::Invalid(ty) => {
                         let msg = format!("cannot use value of type `{ty}` for inline assembly");
-                        self.tcx.dcx().struct_span_err(expr.span, msg).with_note(
+                        self.infcx.dcx().struct_span_err(expr.span, msg).with_note(
                             "only integers, floats, SIMD vectors, pointers and function pointers \
                             can be used as arguments for inline assembly",
                         ).emit();
@@ -203,7 +209,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         let msg = format!(
                             "cannot use value of unsized pointer type `{ty}` for inline assembly"
                         );
-                        self.tcx
+                        self.infcx
                             .dcx()
                             .struct_span_err(expr.span, msg)
                             .with_note("only sized pointers can be used in inline assembly")
@@ -213,8 +219,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         let msg = format!(
                             "cannot use SIMD vector with element type `{ty}` for inline assembly"
                         );
-                        self.tcx.dcx()
-                        .struct_span_err(self.tcx.def_span(did), msg).with_span_note(
+                        self.infcx.dcx()
+                        .struct_span_err(self.tcx().def_span(did), msg).with_span_note(
                             expr.span,
                             "only integers, floats, SIMD vectors, pointers and function pointers \
                             can be used as arguments for inline assembly",
@@ -227,9 +233,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
 
         // Check that the type implements Copy. The only case where this can
         // possibly fail is for SIMD types which don't #[derive(Copy)].
-        if !self.tcx.type_is_copy_modulo_regions(self.typing_env, ty) {
+        if !self.tcx().type_is_copy_modulo_regions(self.typing_env, ty) {
             let msg = "arguments for inline assembly must be copyable";
-            self.tcx
+            self.infcx
                 .dcx()
                 .struct_span_err(expr.span, msg)
                 .with_note(format!("`{ty}` does not implement the Copy trait"))
@@ -249,7 +255,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             if in_asm_ty != asm_ty {
                 let msg = "incompatible types for asm inout argument";
                 let in_expr_ty = self.expr_ty(in_expr);
-                self.tcx
+                self.infcx
                     .dcx()
                     .struct_span_err(vec![in_expr.span, expr.span], msg)
                     .with_span_label(in_expr.span, format!("type `{in_expr_ty}`"))
@@ -268,21 +274,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
 
         // Check the type against the list of types supported by the selected
         // register class.
-        let asm_arch = self.tcx.sess.asm_arch.unwrap();
-        let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
+        let asm_arch = self.tcx().sess.asm_arch.unwrap();
+        let allow_experimental_reg = self.tcx().features().asm_experimental_reg();
         let reg_class = reg.reg_class();
         let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg);
         let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
             let mut err = if !allow_experimental_reg
                 && reg_class.supported_types(asm_arch, true).iter().any(|&(t, _)| t == asm_ty)
             {
-                self.tcx.sess.create_feature_err(
+                self.tcx().sess.create_feature_err(
                     RegisterTypeUnstable { span: expr.span, ty },
                     sym::asm_experimental_reg,
                 )
             } else {
                 let msg = format!("type `{ty}` cannot be used with this register class");
-                let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
+                let mut err = self.infcx.dcx().struct_span_err(expr.span, msg);
                 let supported_tys: Vec<_> =
                     supported_tys.iter().map(|(t, _)| t.to_string()).collect();
                 err.note(format!(
@@ -312,7 +318,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         if let Some(feature) = feature {
             if !self.target_features.contains(feature) {
                 let msg = format!("`{feature}` target feature is not enabled");
-                self.tcx
+                self.infcx
                     .dcx()
                     .struct_span_err(expr.span, msg)
                     .with_note(format!(
@@ -349,7 +355,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     result: default_result,
                     size: default_size,
                 } = reg_class.default_modifier(asm_arch).unwrap();
-                self.tcx.node_span_lint(
+                self.tcx().node_span_lint(
                     lint::builtin::ASM_SUB_REGISTER,
                     expr.hir_id,
                     spans,
@@ -371,11 +377,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     }
 
     pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
-        let Some(asm_arch) = self.tcx.sess.asm_arch else {
-            self.tcx.dcx().delayed_bug("target architecture does not support asm");
+        let Some(asm_arch) = self.tcx().sess.asm_arch else {
+            self.infcx.dcx().delayed_bug("target architecture does not support asm");
             return;
         };
-        let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
+        let allow_experimental_reg = self.tcx().features().asm_experimental_reg();
         for (idx, &(op, op_sp)) in asm.operands.iter().enumerate() {
             // Validate register classes against currently enabled target
             // features. We check that at least one type is available for
@@ -398,13 +404,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     }
                     if let Err(msg) = reg.validate(
                         asm_arch,
-                        self.tcx.sess.relocation_model(),
+                        self.tcx().sess.relocation_model(),
                         self.target_features,
-                        &self.tcx.sess.target,
+                        &self.tcx().sess.target,
                         op.is_clobber(),
                     ) {
                         let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
-                        self.tcx.dcx().span_err(op_sp, msg);
+                        self.infcx.dcx().span_err(op_sp, msg);
                         continue;
                     }
                 }
@@ -444,7 +450,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                                 reg_class.name(),
                                 feature
                             );
-                            self.tcx.dcx().span_err(op_sp, msg);
+                            self.infcx.dcx().span_err(op_sp, msg);
                             // register isn't enabled, don't do more checks
                             continue;
                         }
@@ -458,7 +464,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                                     .intersperse(", ")
                                     .collect::<String>(),
                             );
-                            self.tcx.dcx().span_err(op_sp, msg);
+                            self.infcx.dcx().span_err(op_sp, msg);
                             // register isn't enabled, don't do more checks
                             continue;
                         }
@@ -493,16 +499,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     }
                 }
                 hir::InlineAsmOperand::Const { anon_const } => {
-                    let ty = self.node_ty(anon_const.hir_id);
+                    let ty = self.expr_ty(self.tcx().hir_body(anon_const.body).value);
                     match ty.kind() {
                         ty::Error(_) => {}
                         _ if ty.is_integral() => {}
                         _ => {
-                            self.tcx
+                            self.infcx
                                 .dcx()
                                 .struct_span_err(op_sp, "invalid type for `const` operand")
                                 .with_span_label(
-                                    self.tcx.def_span(anon_const.def_id),
+                                    self.tcx().def_span(anon_const.def_id),
                                     format!("is {} `{}`", ty.kind().article(), ty),
                                 )
                                 .with_help("`const` operands must be of an integer type")
@@ -517,7 +523,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         ty::FnDef(..) => {}
                         ty::Error(_) => {}
                         _ => {
-                            self.tcx
+                            self.infcx
                                 .dcx()
                                 .struct_span_err(op_sp, "invalid `sym` operand")
                                 .with_span_label(
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 6b61d317d3f..883a1acdb30 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1462,7 +1462,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() {
             let mut captures = captures.borrow_mut();
             let remapped = *captures.entry(lifetime).or_insert_with(|| {
-                let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam);
+                let feed =
+                    self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam);
                 feed.def_span(ident.span);
                 feed.def_ident_span(Some(ident.span));
                 feed.def_id()
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index f5e075367f3..e78801dd601 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -78,15 +78,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         if self_ty.span.edition().at_least_rust_2021() {
-            let msg = "expected a type, found a trait";
-            let label = "you can add the `dyn` keyword if you want a trait object";
-            let mut diag =
-                rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
+            let mut diag = rustc_errors::struct_span_code_err!(
+                self.dcx(),
+                self_ty.span,
+                E0782,
+                "{}",
+                "expected a type, found a trait"
+            );
             if self_ty.span.can_be_used_for_suggestions()
                 && !self.maybe_suggest_impl_trait(self_ty, &mut diag)
+                && !self.maybe_suggest_dyn_trait(self_ty, sugg, &mut diag)
             {
-                // FIXME: Only emit this suggestion if the trait is dyn-compatible.
-                diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+                self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag);
             }
             // Check if the impl trait that we are considering is an impl of a local trait.
             self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
@@ -123,6 +126,64 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
+    /// For a struct or enum with an invalid bare trait object field, suggest turning
+    /// it into a generic type bound.
+    fn maybe_suggest_add_generic_impl_trait(
+        &self,
+        self_ty: &hir::Ty<'_>,
+        diag: &mut Diag<'_>,
+    ) -> bool {
+        let tcx = self.tcx();
+
+        let parent_hir_id = tcx.parent_hir_id(self_ty.hir_id);
+        let parent_item = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
+
+        let generics = match tcx.hir_node_by_def_id(parent_item) {
+            hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Struct(variant, generics), ..
+            }) => {
+                if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
+                    return false;
+                }
+                generics
+            }
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(def, generics), .. }) => {
+                if !def
+                    .variants
+                    .iter()
+                    .flat_map(|variant| variant.data.fields().iter())
+                    .any(|field| field.hir_id == parent_hir_id)
+                {
+                    return false;
+                }
+                generics
+            }
+            _ => return false,
+        };
+
+        let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
+            return false;
+        };
+
+        let param = "TUV"
+            .chars()
+            .map(|c| c.to_string())
+            .chain((0..).map(|i| format!("P{i}")))
+            .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
+            .expect("we definitely can find at least one param name to generate");
+        let mut sugg = vec![(self_ty.span, param.to_string())];
+        if let Some(insertion_span) = generics.span_for_param_suggestion() {
+            sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
+        } else {
+            sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
+        }
+        diag.multipart_suggestion_verbose(
+            "you might be missing a type parameter",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+        true
+    }
     /// Make sure that we are in the condition to suggest the blanket implementation.
     fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
         &self,
@@ -171,6 +232,65 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
+    /// Try our best to approximate when adding `dyn` would be helpful for a bare
+    /// trait object.
+    ///
+    /// Right now, this is if the type is either directly nested in another ty,
+    /// or if it's in the tail field within a struct. This approximates what the
+    /// user would've gotten on edition 2015, except for the case where we have
+    /// an *obvious* knock-on `Sized` error.
+    fn maybe_suggest_dyn_trait(
+        &self,
+        self_ty: &hir::Ty<'_>,
+        sugg: Vec<(Span, String)>,
+        diag: &mut Diag<'_>,
+    ) -> bool {
+        let tcx = self.tcx();
+
+        // Look at the direct HIR parent, since we care about the relationship between
+        // the type and the thing that directly encloses it.
+        match tcx.parent_hir_node(self_ty.hir_id) {
+            // These are all generally ok. Namely, when a trait object is nested
+            // into another expression or ty, it's either very certain that they
+            // missed the ty (e.g. `&Trait`) or it's not really possible to tell
+            // what their intention is, so let's not give confusing suggestions and
+            // just mention `dyn`. The user can make up their mind what to do here.
+            hir::Node::Ty(_)
+            | hir::Node::Expr(_)
+            | hir::Node::PatExpr(_)
+            | hir::Node::PathSegment(_)
+            | hir::Node::AssocItemConstraint(_)
+            | hir::Node::TraitRef(_)
+            | hir::Node::Item(_)
+            | hir::Node::WherePredicate(_) => {}
+
+            hir::Node::Field(field) => {
+                // Enums can't have unsized fields, fields can only have an unsized tail field.
+                if let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Struct(variant, _), ..
+                }) = tcx.parent_hir_node(field.hir_id)
+                    && variant
+                        .fields()
+                        .last()
+                        .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
+                {
+                    // Ok
+                } else {
+                    return false;
+                }
+            }
+            _ => return false,
+        }
+
+        // FIXME: Only emit this suggestion if the trait is dyn-compatible.
+        diag.multipart_suggestion_verbose(
+            "you can add the `dyn` keyword if you want a trait object",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+        true
+    }
+
     fn add_generic_param_suggestion(
         &self,
         generics: &hir::Generics<'_>,
diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml
index 86989d1e55b..91da8cb3fc5 100644
--- a/compiler/rustc_hir_pretty/Cargo.toml
+++ b/compiler/rustc_hir_pretty/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2024"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_span = { path = "../rustc_span" }
 # tidy-alphabetical-end
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 147b42c0490..2572ff50eb7 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -16,7 +16,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
 use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::state::MacHeader;
 use rustc_ast_pretty::pprust::{Comments, PrintState};
-use rustc_attr_parsing::{AttributeKind, PrintAttribute};
+use rustc_attr_data_structures::{AttributeKind, PrintAttribute};
 use rustc_hir::{
     BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
     HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
@@ -117,80 +117,6 @@ impl<'a> State<'a> {
                 ));
                 self.hardbreak()
             }
-            hir::Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => {
-                self.word("#[deprecated");
-
-                // There are three possible forms here:
-                // 1. a form with explicit components like
-                //    `#[deprecated(since = "1.2.3", note = "some note", suggestion = "something")]`
-                //    where each component may be present or absent.
-                // 2. `#[deprecated = "message"]`
-                // 3. `#[deprecated]`
-                //
-                // Let's figure out which we need.
-                // If there's a `since` or `suggestion` value, we're definitely in form 1.
-                if matches!(
-                    deprecation.since,
-                    rustc_attr_parsing::DeprecatedSince::RustcVersion(..)
-                        | rustc_attr_parsing::DeprecatedSince::Future
-                        | rustc_attr_parsing::DeprecatedSince::NonStandard(..)
-                ) || deprecation.suggestion.is_some()
-                {
-                    self.word("(");
-                    let mut use_comma = false;
-
-                    match &deprecation.since {
-                        rustc_attr_parsing::DeprecatedSince::RustcVersion(rustc_version) => {
-                            self.word("since = \"");
-                            self.word(format!(
-                                "{}.{}.{}",
-                                rustc_version.major, rustc_version.minor, rustc_version.patch
-                            ));
-                            self.word("\"");
-                            use_comma = true;
-                        }
-                        rustc_attr_parsing::DeprecatedSince::Future => {
-                            self.word("since = \"future\"");
-                            use_comma = true;
-                        }
-                        rustc_attr_parsing::DeprecatedSince::NonStandard(symbol) => {
-                            self.word("since = \"");
-                            self.word(symbol.to_ident_string());
-                            self.word("\"");
-                            use_comma = true;
-                        }
-                        _ => {}
-                    }
-
-                    if let Some(note) = &deprecation.note {
-                        if use_comma {
-                            self.word(", ");
-                        }
-                        self.word("note = \"");
-                        self.word(note.to_ident_string());
-                        self.word("\"");
-                        use_comma = true;
-                    }
-
-                    if let Some(suggestion) = &deprecation.suggestion {
-                        if use_comma {
-                            self.word(", ");
-                        }
-                        self.word("suggestion = \"");
-                        self.word(suggestion.to_ident_string());
-                        self.word("\"");
-                    }
-                } else if let Some(note) = &deprecation.note {
-                    // We're in form 2: `#[deprecated = "message"]`.
-                    self.word(" = \"");
-                    self.word(note.to_ident_string());
-                    self.word("\"");
-                } else {
-                    // We're in form 3: `#[deprecated]`. Nothing to do here.
-                }
-
-                self.word("]");
-            }
             hir::Attribute::Parsed(pa) => {
                 self.word("#[attr=\"");
                 pa.print_attribute(self);
@@ -1544,6 +1470,10 @@ impl<'a> State<'a> {
             hir::ExprKind::MethodCall(segment, receiver, args, _) => {
                 self.print_expr_method_call(segment, receiver, args);
             }
+            hir::ExprKind::Use(expr, _) => {
+                self.print_expr(expr);
+                self.word(".use");
+            }
             hir::ExprKind::Binary(op, lhs, rhs) => {
                 self.print_expr_binary(op, lhs, rhs);
             }
@@ -2294,6 +2224,7 @@ impl<'a> State<'a> {
     fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
         match capture_clause {
             hir::CaptureBy::Value { .. } => self.word_space("move"),
+            hir::CaptureBy::Use { .. } => self.word_space("use"),
             hir::CaptureBy::Ref => {}
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 67419fdf1c3..d7b5c1ed5e1 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -41,8 +41,8 @@ use rustc_abi::ExternAbi;
 use rustc_attr_parsing::InlineAttr;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, struct_span_code_err};
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{self as hir, LangItem};
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer::relate::RelateResult;
 use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
@@ -56,7 +56,7 @@ use rustc_middle::ty::adjustment::{
 };
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AliasTy, GenericArgsRef, Ty, TyCtxt};
 use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -593,6 +593,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
         let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target });
+        let root_obligation = Obligation::new(
+            self.tcx,
+            cause.clone(),
+            self.fcx.param_env,
+            ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]),
+        );
+
+        // If the root `Source: CoerceUnsized<Target>` obligation can't possibly hold,
+        // we don't have to assume that this is unsizing coercion (it will always lead to an error)
+        //
+        // However, we don't want to bail early all the time, since the unholdable obligations
+        // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id<This = U>`),
+        // so we only bail if there (likely) is another way to convert the types.
+        if !self.infcx.predicate_may_hold(&root_obligation) {
+            if let Some(dyn_metadata_adt_def_id) = self.tcx.lang_items().get(LangItem::DynMetadata)
+                && let Some(metadata_type_def_id) = self.tcx.lang_items().get(LangItem::Metadata)
+            {
+                self.probe(|_| {
+                    let ocx = ObligationCtxt::new(&self.infcx);
+
+                    // returns `true` if `<ty as Pointee>::Metadata` is `DynMetadata<_>`
+                    let has_dyn_trait_metadata = |ty| {
+                        let metadata_ty: Result<_, _> = ocx.structurally_normalize_ty(
+                            &ObligationCause::dummy(),
+                            self.fcx.param_env,
+                            Ty::new_alias(
+                                self.tcx,
+                                ty::AliasTyKind::Projection,
+                                AliasTy::new(self.tcx, metadata_type_def_id, [ty]),
+                            ),
+                        );
+
+                        metadata_ty.is_ok_and(|metadata_ty| {
+                            metadata_ty
+                                .ty_adt_def()
+                                .is_some_and(|d| d.did() == dyn_metadata_adt_def_id)
+                        })
+                    };
+
+                    // If both types are raw pointers to a (wrapper over a) trait object,
+                    // this might be a cast like `*const W<dyn Trait> -> *const dyn Trait`.
+                    // So it's better to bail and try that. (even if the cast is not possible, for
+                    // example due to vtables not matching, cast diagnostic will likely still be better)
+                    //
+                    // N.B. use `target`, not `coerce_target` (the latter is a var)
+                    if let &ty::RawPtr(source_pointee, _) = coerce_source.kind()
+                        && let &ty::RawPtr(target_pointee, _) = target.kind()
+                        && has_dyn_trait_metadata(source_pointee)
+                        && has_dyn_trait_metadata(target_pointee)
+                    {
+                        return Err(TypeError::Mismatch);
+                    }
+
+                    Ok(())
+                })?;
+            }
+        }
 
         // Use a FIFO queue for this custom fulfillment procedure.
         //
@@ -601,12 +658,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // and almost never more than 3. By using a SmallVec we avoid an
         // allocation, at the (very small) cost of (occasionally) having to
         // shift subsequent elements down when removing the front element.
-        let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new(
-            self.tcx,
-            cause,
-            self.fcx.param_env,
-            ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target])
-        )];
+        let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![root_obligation];
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 85131f6195f..aa917ee07ff 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1265,7 +1265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     CallableKind::Function
                 };
-                maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
+                maybe_emit_help(def_id, path.segments.last().unwrap().ident, args, callable_kind);
             }
             hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
                 let Some(def_id) =
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 2a89a03e0aa..786e8b876a6 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -362,6 +362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Any expression child of these expressions constitute reads.
                     ExprKind::Array(_)
                     | ExprKind::Call(_, _)
+                    | ExprKind::Use(_, _)
                     | ExprKind::MethodCall(_, _, _, _)
                     | ExprKind::Tup(_)
                     | ExprKind::Binary(_, _, _)
@@ -552,6 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
             ExprKind::Block(body, _) => self.check_expr_block(body, expected),
             ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
+            ExprKind::Use(used_expr, _) => self.check_expr_use(used_expr, expected),
             ExprKind::MethodCall(segment, receiver, args, _) => {
                 self.check_expr_method_call(expr, segment, receiver, args, expected)
             }
@@ -1616,6 +1618,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
+    /// Checks use `x.use`.
+    fn check_expr_use(
+        &self,
+        used_expr: &'tcx hir::Expr<'tcx>,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        self.check_expr_with_expectation(used_expr, expected)
+    }
+
     fn check_expr_cast(
         &self,
         e: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index c0617119d67..9ff7eeb2368 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -47,6 +47,21 @@ pub trait Delegate<'tcx> {
     /// the id of the binding in the pattern `pat`.
     fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
 
+    /// The value found at `place` is used, depending
+    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
+    ///
+    /// Use of a `Copy` type in a ByUse context is considered a use
+    /// by `ImmBorrow` and `borrow` is called instead. This is because
+    /// a shared borrow is the "minimum access" that would be needed
+    /// to perform a copy.
+    ///
+    ///
+    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
+    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
+    /// id will be the id of the expression `expr` but the place itself will have
+    /// the id of the binding in the pattern `pat`.
+    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
+
     /// The value found at `place` is being borrowed with kind `bk`.
     /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
     fn borrow(
@@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
         (**self).consume(place_with_id, diag_expr_id)
     }
 
+    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        (**self).use_cloned(place_with_id, diag_expr_id)
+    }
+
     fn borrow(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> {
 
     fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
 
+    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
+
     fn body_owner_def_id(&self) -> LocalDefId;
 
     fn tcx(&self) -> TyCtxt<'tcx>;
@@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
         self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
     }
 
+    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
+    }
+
     fn body_owner_def_id(&self) -> LocalDefId {
         self.body_id
     }
@@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
         self.0.type_is_copy_modulo_regions(ty)
     }
 
+    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.0.type_is_use_cloned_modulo_regions(ty)
+    }
+
     fn body_owner_def_id(&self) -> LocalDefId {
         self.1
     }
@@ -295,6 +324,24 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         }
     }
 
+    pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id);
+
+        // `x.use` will do one of the following
+        // * if it implements `Copy`, it will be a copy
+        // * if it implements `UseCloned`, it will be a call to `clone`
+        // * otherwise, it is a move
+        //
+        // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned`
+        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
+            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
+        } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
+            self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id);
+        } else {
+            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
+        }
+    }
+
     fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> {
         for expr in exprs {
             self.consume_expr(expr)?;
@@ -313,6 +360,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         Ok(())
     }
 
+    pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
+        debug!("consume_or_clone_expr(expr={:?})", expr);
+
+        let place_with_id = self.cat_expr(expr)?;
+        self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
+        self.walk_expr(expr)?;
+        Ok(())
+    }
+
     fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
         let place_with_id = self.cat_expr(expr)?;
         self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
@@ -366,6 +422,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 self.consume_exprs(args)?;
             }
 
+            hir::ExprKind::Use(expr, _) => {
+                self.consume_or_clone_expr(expr)?;
+            }
+
             hir::ExprKind::MethodCall(.., receiver, args, _) => {
                 // callee.m(args)
                 self.consume_expr(receiver)?;
@@ -1085,6 +1145,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                         ty::UpvarCapture::ByValue => {
                             self.consume_or_copy(&place_with_id, place_with_id.hir_id);
                         }
+                        ty::UpvarCapture::ByUse => {
+                            self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
+                        }
                         ty::UpvarCapture::ByRef(upvar_borrow) => {
                             self.delegate.borrow_mut().borrow(
                                 &place_with_id,
@@ -1386,6 +1449,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
 
             hir::ExprKind::AddrOf(..)
             | hir::ExprKind::Call(..)
+            | hir::ExprKind::Use(..)
             | hir::ExprKind::Assign(..)
             | hir::ExprKind::AssignOp(..)
             | hir::ExprKind::Closure { .. }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index db947b6744d..ac911c20222 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -99,22 +99,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
         for (asm, hir_id) in deferred_asm_checks.drain(..) {
             let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id);
-            let expr_ty = |expr: &hir::Expr<'tcx>| {
-                let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
-                let ty = self.resolve_vars_if_possible(ty);
-                if ty.has_non_region_infer() {
-                    Ty::new_misc_error(self.tcx)
-                } else {
-                    self.tcx.erase_regions(ty)
-                }
-            };
-            let node_ty = |hir_id: HirId| self.typeck_results.borrow().node_type(hir_id);
             InlineAsmCtxt::new(
-                self.tcx,
                 enclosing_id,
+                &self.infcx,
                 self.typing_env(self.param_env),
-                expr_ty,
-                node_ty,
+                &*self.typeck_results.borrow(),
             )
             .check_asm(asm);
         }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 9a0b2247058..f570d0d8a0d 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -671,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let (place, capture_kind) = match capture_clause {
                     hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
+                    hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind),
                     hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
                 };
 
@@ -1165,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let ty = match closure_clause {
             hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value
-            hir::CaptureBy::Ref => {
+            hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {
                 // For non move closure the capture kind is the max capture kind of all captures
                 // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
                 let mut max_capture_info = root_var_min_capture_list.first().unwrap().info;
@@ -1292,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
                     return Some(diagnostics_info);
                 }
-                hir::CaptureBy::Ref => {}
+                hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {}
             }
 
             return None;
@@ -1305,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for captured_place in root_var_min_capture_list.iter() {
             match captured_place.info.capture_kind {
                 // Only care about captures that are moved into the closure
-                ty::UpvarCapture::ByValue => {
+                ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
                     projections_list.push(captured_place.place.projections.as_slice());
                     diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
                         source_expr: captured_place.info.path_expr_id,
@@ -1689,10 +1690,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             //
             // If the data will be moved out of this place, then the place will be truncated
             // at the first Deref in `adjust_for_move_closure` and then moved into the closure.
+            //
+            // For example:
+            //
+            // struct Buffer<'a> {
+            //     x: &'a String,
+            //     y: Vec<u8>,
+            // }
+            //
+            // fn get<'a>(b: Buffer<'a>) -> impl Sized + 'a {
+            //     let c = move || b.x;
+            //     drop(b);
+            //     c
+            // }
+            //
+            // Even though the closure is declared as move, when we are capturing borrowed data (in
+            // this case, *b.x) we prefer to capture by reference.
+            // Otherwise you'd get an error in 2021 immediately because you'd be trying to take
+            // ownership of the (borrowed) String or else you'd take ownership of b, as in 2018 and
+            // before, which is also an error.
             hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => {
                 ty::UpvarCapture::ByValue
             }
-            hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => {
+            hir::CaptureBy::Use { .. } if !place.deref_tys().any(Ty::is_ref) => {
+                ty::UpvarCapture::ByUse
+            }
+            hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => {
                 ty::UpvarCapture::ByRef(BorrowKind::Immutable)
             }
         }
@@ -1927,7 +1950,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
     region: ty::Region<'tcx>,
 ) -> Ty<'tcx> {
     match capture_kind {
-        ty::UpvarCapture::ByValue => ty,
+        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty,
         ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()),
     }
 }
@@ -2024,6 +2047,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
+    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+        assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
+
+        self.capture_information.push((
+            place_with_id.place.clone(),
+            ty::CaptureInfo {
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
+                capture_kind: ty::UpvarCapture::ByUse,
+            },
+        ));
+    }
+
+    #[instrument(skip(self), level = "debug")]
     fn borrow(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -2164,6 +2202,20 @@ fn adjust_for_move_closure(
     (place, ty::UpvarCapture::ByValue)
 }
 
+/// Truncate deref of any reference.
+fn adjust_for_use_closure(
+    mut place: Place<'_>,
+    mut kind: ty::UpvarCapture,
+) -> (Place<'_>, ty::UpvarCapture) {
+    let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
+
+    if let Some(idx) = first_deref {
+        truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
+    }
+
+    (place, ty::UpvarCapture::ByUse)
+}
+
 /// Adjust closure capture just that if taking ownership of data, only move data
 /// from enclosing stack frame.
 fn adjust_for_non_move_closure(
@@ -2174,7 +2226,7 @@ fn adjust_for_non_move_closure(
         place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
 
     match kind {
-        ty::UpvarCapture::ByValue => {
+        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
             if let Some(idx) = contains_deref {
                 truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
             }
@@ -2219,6 +2271,7 @@ fn construct_capture_kind_reason_string<'tcx>(
 
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByUse => "ByUse".into(),
         ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
     };
 
@@ -2240,6 +2293,7 @@ fn construct_capture_info_string<'tcx>(
 
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByUse => "ByUse".into(),
         ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
     };
     format!("{place_str} -> {capture_kind_str}")
@@ -2335,8 +2389,11 @@ fn determine_capture_info(
     // expressions.
     let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
         (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
+        (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true,
         (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
-        (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
+        (ty::UpvarCapture::ByValue, _)
+        | (ty::UpvarCapture::ByUse, _)
+        | (ty::UpvarCapture::ByRef(_), _) => false,
     };
 
     if eq_capture_kind {
@@ -2346,10 +2403,20 @@ fn determine_capture_info(
         }
     } else {
         // We select the CaptureKind which ranks higher based the following priority order:
-        // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
+        // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow
         match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-            (ty::UpvarCapture::ByValue, _) => capture_info_a,
-            (_, ty::UpvarCapture::ByValue) => capture_info_b,
+            (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByValue)
+            | (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByUse) => {
+                bug!("Same capture can't be ByUse and ByValue at the same time")
+            }
+            (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue)
+            | (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse)
+            | (ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse, ty::UpvarCapture::ByRef(_)) => {
+                capture_info_a
+            }
+            (ty::UpvarCapture::ByRef(_), ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse) => {
+                capture_info_b
+            }
             (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
                 match (ref_a, ref_b) {
                     // Take LHS:
@@ -2401,7 +2468,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>(
         }
 
         ty::UpvarCapture::ByRef(..) => {}
-        ty::UpvarCapture::ByValue => {}
+        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
     }
 
     place.projections.truncate(len);
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index 4939bfb3a1c..db0a5841887 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-rand = "0.8.4"
+rand = "0.9.0"
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 4c664ea6ba0..9cec2702a41 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -123,7 +123,7 @@ pub(crate) fn read_file(
 
     // Check HEADER_FORMAT_VERSION
     {
-        debug_assert!(::std::mem::size_of_val(&HEADER_FORMAT_VERSION) == 2);
+        debug_assert!(size_of_val(&HEADER_FORMAT_VERSION) == 2);
         let mut header_format_version = [0u8; 2];
         file.read_exact(&mut header_format_version)?;
         let header_format_version =
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 19cca48af61..76a1ff3cf38 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -108,7 +108,7 @@ use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
-use rand::{RngCore, thread_rng};
+use rand::{RngCore, rng};
 use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::svh::Svh;
@@ -445,7 +445,7 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
 fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
     let timestamp = timestamp_to_string(SystemTime::now());
     debug!("generate_session_dir_path: timestamp = {}", timestamp);
-    let random_number = thread_rng().next_u32();
+    let random_number = rng().next_u32();
     debug!("generate_session_dir_path: random_number = {}", random_number);
 
     // Chop the first 3 characters off the timestamp. Those 3 bytes will be zero for a while.
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 6dc044a6d38..598409c9051 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -1,7 +1,9 @@
 use std::marker::PhantomData;
+#[cfg(not(feature = "nightly"))]
+use std::mem;
 use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl};
 use std::rc::Rc;
-use std::{fmt, iter, mem, slice};
+use std::{fmt, iter, slice};
 
 use Chunk::*;
 #[cfg(feature = "nightly")]
@@ -14,7 +16,7 @@ use crate::{Idx, IndexVec};
 mod tests;
 
 type Word = u64;
-const WORD_BYTES: usize = mem::size_of::<Word>();
+const WORD_BYTES: usize = size_of::<Word>();
 const WORD_BITS: usize = WORD_BYTES * 8;
 
 // The choice of chunk size has some trade-offs.
diff --git a/compiler/rustc_index/src/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs
index 381d79c24fc..5b0ca4b2b92 100644
--- a/compiler/rustc_index/src/vec/tests.rs
+++ b/compiler/rustc_index/src/vec/tests.rs
@@ -9,8 +9,6 @@ crate::newtype_index! {
 
 #[test]
 fn index_size_is_optimized() {
-    use std::mem::size_of;
-
     assert_eq!(size_of::<MyIdx>(), 4);
     // Uses 0xFFFF_FFFB
     assert_eq!(size_of::<Option<MyIdx>>(), 4);
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 74663e6b4bb..cd4106ebf83 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -683,6 +683,10 @@ impl<'tcx> LateContext<'tcx> {
         self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
     }
 
+    pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
+    }
+
     /// Gets the type-checking results for the current body,
     /// or `None` if outside a body.
     pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index fd6b3e90ada..91c7922638d 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -159,7 +159,10 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
         ExprKind::Path(..) => false,
 
         // Calls return rvalues.
-        ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
+        ExprKind::Call(..)
+        | ExprKind::MethodCall(..)
+        | ExprKind::Use(..)
+        | ExprKind::Binary(..) => true,
 
         // Inner blocks are rvalues.
         ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index 59e38a882dd..58efca5e994 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
             return;
         }
 
-        // At least one of the fields with a default value have been overriden in
+        // At least one of the fields with a default value have been overridden in
         // the `Default` implementation. We suggest removing it and relying on `..`
         // instead.
         let any_default_field_given =
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index d22515d62d6..23d6efa0508 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -74,7 +74,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
 
     fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: HirId) {
         lint_callback!(self, check_mod, m, n);
-        hir_visit::walk_mod(self, m, n);
+        hir_visit::walk_mod(self, m);
     }
 }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 10b85be2cfb..592c934997c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -73,7 +73,6 @@ declare_lint_pass! {
         NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
         NON_CONTIGUOUS_RANGE_ENDPOINTS,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
-        ORDER_DEPENDENT_TRAIT_OBJECTS,
         OUT_OF_SCOPE_MACRO_CALLS,
         OVERLAPPING_RANGE_ENDPOINTS,
         PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -1502,42 +1501,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `order_dependent_trait_objects` lint detects a trait coherency
-    /// violation that would allow creating two trait impls for the same
-    /// dynamic trait object involving marker traits.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// pub trait Trait {}
-    ///
-    /// impl Trait for dyn Send + Sync { }
-    /// impl Trait for dyn Sync + Send { }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// A previous bug caused the compiler to interpret traits with different
-    /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types
-    /// when they were intended to be treated the same. This allowed code to
-    /// define separate trait implementations when there should be a coherence
-    /// error. This is a [future-incompatible] lint to transition this to a
-    /// hard error in the future. See [issue #56484] for more details.
-    ///
-    /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484
-    /// [future-incompatible]: ../index.md#future-incompatible-lints
-    pub ORDER_DEPENDENT_TRAIT_OBJECTS,
-    Deny,
-    "trait-object types were treated as different depending on marker-trait order",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
-    };
-}
-
-declare_lint! {
     /// The `coherence_leak_check` lint detects conflicting implementations of
     /// a trait that are only distinguished by the old leak-check code.
     ///
@@ -2710,7 +2673,7 @@ declare_lint! {
     ///
     /// ```rust
     /// const fn foo<T>() -> usize {
-    ///     if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
+    ///     if size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
     ///         4
     ///     } else {
     ///         8
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 6e607baebb5..bc3d4d6f83a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -484,7 +484,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
 
   if (ArgsCstrBuff != nullptr) {
 #if LLVM_VERSION_GE(20, 0)
-    int buffer_offset = 0;
+    size_t buffer_offset = 0;
     assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
     auto Arg0 = std::string(ArgsCstrBuff);
     buffer_offset = Arg0.size() + 1;
@@ -502,7 +502,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     Options.MCOptions.Argv0 = Arg0;
     Options.MCOptions.CommandlineArgs = CommandlineArgs;
 #else
-    int buffer_offset = 0;
+    size_t buffer_offset = 0;
     assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
 
     const size_t arg0_len = std::strlen(ArgsCstrBuff);
@@ -511,13 +511,13 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     arg0[arg0_len] = '\0';
     buffer_offset += arg0_len + 1;
 
-    const int num_cmd_arg_strings = std::count(
+    const size_t num_cmd_arg_strings = std::count(
         &ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0');
 
     std::string *cmd_arg_strings = new std::string[num_cmd_arg_strings];
-    for (int i = 0; i < num_cmd_arg_strings; ++i) {
+    for (size_t i = 0; i < num_cmd_arg_strings; ++i) {
       assert(buffer_offset < ArgsCstrBuffLen);
-      const int len = std::strlen(ArgsCstrBuff + buffer_offset);
+      const size_t len = std::strlen(ArgsCstrBuff + buffer_offset);
       cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len);
       buffer_offset += len + 1;
     }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index aea2a8dd097..53df59930f4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -152,8 +152,12 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) {
 }
 
 extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M,
-                                            const char *Triple) {
-  unwrap(M)->setTargetTriple(Triple::normalize(Triple));
+                                            const char *Target) {
+#if LLVM_VERSION_GE(21, 0)
+  unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target)));
+#else
+  unwrap(M)->setTargetTriple(Triple::normalize(Target));
+#endif
 }
 
 extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) {
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index aebd2181f31..43c1af642dd 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -14,7 +14,8 @@ rustc_abi = { path = "../rustc_abi" }
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_ast_ir = { path = "../rustc_ast_ir" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index fad8c7dcbcb..c85af81ee25 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -1356,7 +1356,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
             self.submodules.push(item.owner_id);
             // A module collector does not recurse inside nested modules.
             if self.crate_collector {
-                intravisit::walk_mod(self, module, item.hir_id());
+                intravisit::walk_mod(self, module);
             }
         } else {
             intravisit::walk_item(self, item)
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 311bc60c3cd..a94ead161c3 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Align;
 use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs;
-use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::Symbol;
 use rustc_target::spec::SanitizerSet;
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 2260cad41b9..ec128c8c478 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -4,7 +4,7 @@
 use std::num::NonZero;
 
 use rustc_ast::NodeId;
-use rustc_attr_parsing::{
+use rustc_attr_data_structures::{
     self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
 };
 use rustc_data_structures::unord::UnordMap;
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
index cc6389e2989..fea5038e6dd 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
@@ -223,8 +223,8 @@ impl<D: TyDecoder> Decodable<D> for InitMaskMaterialized {
 // large.
 impl hash::Hash for InitMaskMaterialized {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
-        const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / std::mem::size_of::<Block>();
-        const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / std::mem::size_of::<Block>();
+        const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / size_of::<Block>();
+        const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / size_of::<Block>();
 
         // Partially hash the `blocks` buffer when it is large. To limit collisions with common
         // prefixes and suffixes, we hash the length and some slices of the buffer.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index c48cfffa05c..2675b7e0fc5 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -573,7 +573,7 @@ pub fn write_target_uint(
 #[inline]
 pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, io::Error> {
     // This u128 holds an "any-size uint" (since smaller uints can fits in it)
-    let mut buf = [0u8; std::mem::size_of::<u128>()];
+    let mut buf = [0u8; size_of::<u128>()];
     // So we do not read exactly 16 bytes into the u128, just the "payload".
     let uint = match endianness {
         Endian::Little => {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index ea0bb5feb12..83857ab6c5c 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -332,13 +332,13 @@ pub struct Body<'tcx> {
     ///
     /// ```rust
     /// fn test<T>() {
-    ///     let _ = [0; std::mem::size_of::<*mut T>()];
+    ///     let _ = [0; size_of::<*mut T>()];
     /// }
     /// ```
     ///
     /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization
     /// removed the last mention of all generic params. We do not want to rely on optimizations and
-    /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
+    /// potentially allow things like `[u8; size_of::<T>() * 0]` due to this.
     pub is_polymorphic: bool,
 
     /// The phase at which this MIR should be "injected" into the compilation process.
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 58d5c94d033..897119c0712 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -2,7 +2,7 @@ use std::fmt;
 use std::hash::Hash;
 
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxIndexMap;
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index cbd60920bc5..907618e428f 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -27,7 +27,7 @@ pub type Erase<T: EraseType> = Erased<impl Copy>;
 pub fn erase<T: EraseType>(src: T) -> Erase<T> {
     // Ensure the sizes match
     const {
-        if std::mem::size_of::<T>() != std::mem::size_of::<T::Result>() {
+        if size_of::<T>() != size_of::<T::Result>() {
             panic!("size of T must match erased type T::Result")
         }
     };
@@ -231,9 +231,9 @@ trivial! {
     bool,
     Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>,
     Option<rustc_ast::expand::allocator::AllocatorKind>,
-    Option<rustc_attr_parsing::ConstStability>,
-    Option<rustc_attr_parsing::DefaultBodyStability>,
-    Option<rustc_attr_parsing::Stability>,
+    Option<rustc_attr_data_structures::ConstStability>,
+    Option<rustc_attr_data_structures::DefaultBodyStability>,
+    Option<rustc_attr_data_structures::Stability>,
     Option<rustc_data_structures::svh::Svh>,
     Option<rustc_hir::def::DefKind>,
     Option<rustc_hir::CoroutineKind>,
@@ -256,10 +256,10 @@ trivial! {
     Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
     rustc_abi::ReprOptions,
     rustc_ast::expand::allocator::AllocatorKind,
-    rustc_attr_parsing::ConstStability,
-    rustc_attr_parsing::DefaultBodyStability,
-    rustc_attr_parsing::Deprecation,
-    rustc_attr_parsing::Stability,
+    rustc_attr_data_structures::ConstStability,
+    rustc_attr_data_structures::DefaultBodyStability,
+    rustc_attr_data_structures::Deprecation,
+    rustc_attr_data_structures::Stability,
     rustc_data_structures::svh::Svh,
     rustc_errors::ErrorGuaranteed,
     rustc_hir::Constness,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4ad4427594c..c8708857565 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -41,7 +41,7 @@ use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Span, Symbol};
 use rustc_target::spec::PanicStrategy;
-use {rustc_abi as abi, rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir};
 
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintExpectation;
@@ -999,12 +999,6 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(
-        key: DefId
-    ) -> Option<ty::EarlyBinder<'tcx, ty::Ty<'tcx>>> {
-        desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) }
-    }
-
     /// Maps a `DefId` of a type to a list of its inherent impls.
     /// Contains implementations of methods that are inherent to a type.
     /// Methods in these implementations don't need to be exported.
@@ -1533,6 +1527,11 @@ rustc_queries! {
     query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Copy`", env.value }
     }
+    /// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`,
+    /// `ty.is_use_cloned()`, etc, since that will prune the environment where possible.
+    query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
+        desc { "computing whether `{}` is `UseCloned`", env.value }
+    }
     /// Query backing `Ty::is_sized`.
     query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Sized`", env.value }
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 66a9e5fed4c..4834444ed1d 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -165,7 +165,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-#[inline]
+#[inline(always)]
 pub fn query_get_at<'tcx, Cache>(
     tcx: TyCtxt<'tcx>,
     execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
@@ -370,7 +370,7 @@ macro_rules! define_callbacks {
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
                 const _: () = {
-                    if mem::size_of::<Key<'static>>() > 88 {
+                    if size_of::<Key<'static>>() > 88 {
                         panic!("{}", concat!(
                             "the query `",
                             stringify!($name),
@@ -386,7 +386,7 @@ macro_rules! define_callbacks {
                 #[cfg(target_pointer_width = "64")]
                 #[cfg(not(feature = "rustc_randomized_layouts"))]
                 const _: () = {
-                    if mem::size_of::<Value<'static>>() > 64 {
+                    if size_of::<Value<'static>>() > 64 {
                         panic!("{}", concat!(
                             "the query `",
                             stringify!($name),
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 72f31cec008..f7b98d935d4 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -315,6 +315,14 @@ pub enum ExprKind<'tcx> {
         /// (e.g. `foo(a, b)` in `x.foo(a, b)`).
         fn_span: Span,
     },
+    /// A use expression `x.use`.
+    ByUse {
+        /// The expression on which use is applied.
+        expr: ExprId,
+        /// The span of use, without the dot and receiver
+        /// (e.g. `use` in `x.use`).
+        span: Span,
+    },
     /// A *non-overloaded* dereference.
     Deref {
         arg: ExprId,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index a9df4d1625b..d208692f4e7 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -59,6 +59,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                 visitor.visit_expr(&visitor.thir()[arg]);
             }
         }
+        ByUse { expr, span: _ } => {
+            visitor.visit_expr(&visitor.thir()[expr]);
+        }
         Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
         Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
             visitor.visit_expr(&visitor.thir()[lhs]);
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 3605f2402e7..5d9b1ddfa38 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -51,6 +51,9 @@ pub enum UpvarCapture {
     /// depending on inference.
     ByValue,
 
+    /// Upvar is captured by use. This is true when the closure is labeled `use`.
+    ByUse,
+
     /// Upvar is captured by reference.
     ByRef(BorrowKind),
 }
@@ -178,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> {
 
     pub fn is_by_ref(&self) -> bool {
         match self.info.capture_kind {
-            ty::UpvarCapture::ByValue => false,
+            ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false,
             ty::UpvarCapture::ByRef(..) => true,
         }
     }
@@ -214,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
         if !self.is_closure_like(def_id.to_def_id()) {
             return &[];
-        };
+        }
         self.closure_typeinfo(def_id).captures
     }
 }
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 7c9280fae16..9f5e31d894c 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -408,7 +408,7 @@ macro_rules! from_x_for_scalar_int {
                 fn from(u: $ty) -> Self {
                     Self {
                         data: u128::from(u),
-                        size: NonZero::new(std::mem::size_of::<$ty>() as u8).unwrap(),
+                        size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
                     }
                 }
             }
@@ -424,7 +424,7 @@ macro_rules! from_scalar_int_for_x {
                 fn from(int: ScalarInt) -> Self {
                     // The `unwrap` cannot fail because to_bits (if it succeeds)
                     // is guaranteed to return a value that fits into the size.
-                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>()))
+                    int.to_bits(Size::from_bytes(size_of::<$ty>()))
                        .try_into().unwrap()
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d0aa2b8cbda..edba2a2530f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1327,6 +1327,11 @@ pub struct TyCtxt<'tcx> {
     gcx: &'tcx GlobalCtxt<'tcx>,
 }
 
+// Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its
+// field are asserted to implement these traits below, so this is trivially safe, and it greatly
+// speeds-up compilation of this crate and its dependents.
+unsafe impl DynSend for TyCtxt<'_> {}
+unsafe impl DynSync for TyCtxt<'_> {}
 fn _assert_tcx_fields() {
     sync::assert_dyn_sync::<&'_ GlobalCtxt<'_>>();
     sync::assert_dyn_send::<&'_ GlobalCtxt<'_>>();
@@ -1885,7 +1890,7 @@ impl<'tcx> TyCtxtAt<'tcx> {
     pub fn create_def(
         self,
         parent: LocalDefId,
-        name: Symbol,
+        name: Option<Symbol>,
         def_kind: DefKind,
     ) -> TyCtxtFeed<'tcx, LocalDefId> {
         let feed = self.tcx.create_def(parent, name, def_kind);
@@ -1900,7 +1905,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn create_def(
         self,
         parent: LocalDefId,
-        name: Symbol,
+        name: Option<Symbol>,
         def_kind: DefKind,
     ) -> TyCtxtFeed<'tcx, LocalDefId> {
         let data = def_kind.def_path_data(name);
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 27576a2ec4a..f24910477dc 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -2,7 +2,6 @@
 
 use core::intrinsics;
 use std::marker::PhantomData;
-use std::mem;
 use std::num::NonZero;
 use std::ptr::NonNull;
 
@@ -176,17 +175,17 @@ impl<'tcx> GenericArgKind<'tcx> {
         let (tag, ptr) = match self {
             GenericArgKind::Lifetime(lt) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0);
+                assert_eq!(align_of_val(&*lt.0.0) & TAG_MASK, 0);
                 (REGION_TAG, NonNull::from(lt.0.0).cast())
             }
             GenericArgKind::Type(ty) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
+                assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0);
                 (TYPE_TAG, NonNull::from(ty.0.0).cast())
             }
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
+                assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0);
                 (CONST_TAG, NonNull::from(ct.0.0).cast())
             }
         };
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 98ca71b86be..b99148f3368 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -203,7 +203,7 @@ impl<'tcx> Instance<'tcx> {
         if !tcx.sess.opts.share_generics()
             // However, if the def_id is marked inline(never), then it's fine to just reuse the
             // upstream monomorphization.
-            && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_parsing::InlineAttr::Never
+            && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_data_structures::InlineAttr::Never
         {
             return None;
         }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 272bb0cc915..ebb6a8c08a5 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,20 +1,17 @@
-use std::num::NonZero;
 use std::ops::Bound;
 use std::{cmp, fmt};
 
 use rustc_abi::{
-    AddressSpace, Align, BackendRepr, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData,
-    PointeeInfo, PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
+    AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
+    PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
     TyAbiInterface, VariantIdx, Variants,
 };
 use rustc_error_messages::DiagMessage;
 use rustc_errors::{
     Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
 };
-use rustc_hashes::Hash64;
 use rustc_hir::LangItem;
 use rustc_hir::def_id::DefId;
-use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
 use rustc_session::config::OptLevel;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
@@ -185,12 +182,7 @@ pub const WIDE_PTR_ADDR: usize = 0;
 /// - For a slice, this is the length.
 pub const WIDE_PTR_EXTRA: usize = 1;
 
-/// The maximum supported number of lanes in a SIMD vector.
-///
-/// This value is selected based on backend support:
-/// * LLVM does not appear to have a vector width limit.
-/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
-pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
+pub const MAX_SIMD_LANES: u64 = rustc_abi::MAX_SIMD_LANES;
 
 /// Used in `check_validity_requirement` to indicate the kind of initialization
 /// that is checked to be valid
@@ -762,11 +754,9 @@ where
         variant_index: VariantIdx,
     ) -> TyAndLayout<'tcx> {
         let layout = match this.variants {
-            Variants::Single { index }
-                // If all variants but one are uninhabited, the variant layout is the enum layout.
-                if index == variant_index =>
-            {
-                this.layout
+            // If all variants but one are uninhabited, the variant layout is the enum layout.
+            Variants::Single { index } if index == variant_index => {
+                return this;
             }
 
             Variants::Single { .. } | Variants::Empty => {
@@ -783,29 +773,18 @@ where
                 }
 
                 let fields = match this.ty.kind() {
-                    ty::Adt(def, _) if def.variants().is_empty() =>
-                        bug!("for_variant called on zero-variant enum {}", this.ty),
+                    ty::Adt(def, _) if def.variants().is_empty() => {
+                        bug!("for_variant called on zero-variant enum {}", this.ty)
+                    }
                     ty::Adt(def, _) => def.variant(variant_index).fields.len(),
                     _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
                 };
-                tcx.mk_layout(LayoutData {
-                    variants: Variants::Single { index: variant_index },
-                    fields: match NonZero::new(fields) {
-                        Some(fields) => FieldsShape::Union(fields),
-                        None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() },
-                    },
-                    backend_repr: BackendRepr::Memory { sized: true },
-                    largest_niche: None,
-                    uninhabited: true,
-                    align: tcx.data_layout.i8_align,
-                    size: Size::ZERO,
-                    max_repr_align: None,
-                    unadjusted_abi_align: tcx.data_layout.i8_align.abi,
-                    randomization_seed: Hash64::ZERO,
-                })
+                tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields))
             }
 
-            Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()),
+            Variants::Multiple { ref variants, .. } => {
+                cx.tcx().mk_layout(variants[variant_index].clone())
+            }
         };
 
         assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 6718493f6b3..0fd370a5619 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -93,7 +93,7 @@ impl<H, T> RawList<H, T> {
         T: Copy,
     {
         assert!(!mem::needs_drop::<T>());
-        assert!(mem::size_of::<T>() != 0);
+        assert!(size_of::<T>() != 0);
         assert!(!slice.is_empty());
 
         let (layout, _offset) =
@@ -155,7 +155,7 @@ macro_rules! impl_list_empty {
                 static EMPTY: ListSkeleton<$header_ty, MaxAlign> =
                     ListSkeleton { header: $header_init, len: 0, data: [] };
 
-                assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>());
+                assert!(align_of::<T>() <= align_of::<MaxAlign>());
 
                 // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all
                 // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 527509af05f..c5509c0a608 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -17,7 +17,7 @@ use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::num::NonZero;
 use std::ptr::NonNull;
-use std::{fmt, mem, str};
+use std::{fmt, str};
 
 pub use adt::*;
 pub use assoc::*;
@@ -27,7 +27,8 @@ pub use intrinsic::IntrinsicDef;
 use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
-use rustc_attr_parsing::AttributeKind;
+pub use rustc_ast_ir::{Movability, Mutability, try_visit};
+use rustc_attr_data_structures::AttributeKind;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -51,7 +52,7 @@ pub use rustc_type_ir::relate::VarianceDiagInfo;
 pub use rustc_type_ir::*;
 use tracing::{debug, instrument};
 pub use vtable::*;
-use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir};
 
 pub use self::closure::{
     BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo,
@@ -637,12 +638,12 @@ impl<'tcx> TermKind<'tcx> {
         let (tag, ptr) = match self {
             TermKind::Ty(ty) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
+                assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0);
                 (TYPE_TAG, NonNull::from(ty.0.0).cast())
             }
             TermKind::Const(ct) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
+                assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0);
                 (CONST_TAG, NonNull::from(ct.0.0).cast())
             }
         };
@@ -1414,39 +1415,6 @@ pub enum ImplOverlapKind {
         /// Whether or not the impl is permitted due to the trait being a `#[marker]` trait
         marker: bool,
     },
-    /// These impls are allowed to overlap, but that raises an
-    /// issue #33140 future-compatibility warning (tracked in #56484).
-    ///
-    /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's
-    /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different.
-    ///
-    /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied on
-    /// that difference, doing what reduces to the following set of impls:
-    ///
-    /// ```compile_fail,(E0119)
-    /// trait Trait {}
-    /// impl Trait for dyn Send + Sync {}
-    /// impl Trait for dyn Sync + Send {}
-    /// ```
-    ///
-    /// Obviously, once we made these types be identical, that code causes a coherence
-    /// error and a fairly big headache for us. However, luckily for us, the trait
-    /// `Trait` used in this case is basically a marker trait, and therefore having
-    /// overlapping impls for it is sound.
-    ///
-    /// To handle this, we basically regard the trait as a marker trait, with an additional
-    /// future-compatibility warning. To avoid accidentally "stabilizing" this feature,
-    /// it has the following restrictions:
-    ///
-    /// 1. The trait must indeed be a marker-like trait (i.e., no items), and must be
-    /// positive impls.
-    /// 2. The trait-ref of both impls must be equal.
-    /// 3. The trait-ref of both impls must be a trait object type consisting only of
-    /// marker traits.
-    /// 4. Neither of the impls can have any where-clauses.
-    ///
-    /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed.
-    FutureCompatOrderDepTraitObjects,
 }
 
 /// Useful source information about where a desugared associated type for an
@@ -1624,7 +1592,7 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    /// Returns `true` if the impls are the same polarity and the trait either
+    /// Returns `Some` if the impls are the same polarity and the trait either
     /// has no items or is annotated `#[marker]` and prevents item overrides.
     #[instrument(level = "debug", skip(self), ret)]
     pub fn impls_are_allowed_to_overlap(
@@ -1665,18 +1633,6 @@ impl<'tcx> TyCtxt<'tcx> {
             return Some(ImplOverlapKind::Permitted { marker: true });
         }
 
-        if let Some(self_ty1) =
-            self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id1)
-            && let Some(self_ty2) =
-                self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id2)
-        {
-            if self_ty1 == self_ty2 {
-                return Some(ImplOverlapKind::FutureCompatOrderDepTraitObjects);
-            } else {
-                debug!("found {self_ty1:?} != {self_ty2:?}");
-            }
-        }
-
         None
     }
 
@@ -1757,7 +1713,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Gets all attributes.
     ///
-    /// To see if an item has a specific attribute, you should use [`rustc_attr_parsing::find_attr!`] so you can use matching.
+    /// To see if an item has a specific attribute, you should use [`rustc_attr_data_structures::find_attr!`] so you can use matching.
     pub fn get_all_attrs(
         self,
         did: impl Into<DefId>,
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 8eaf0a58f70..71fc38cb7ed 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -80,10 +80,10 @@ trivially_parameterized_over_tcx! {
     rustc_ast::Attribute,
     rustc_ast::DelimArgs,
     rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
-    rustc_attr_parsing::ConstStability,
-    rustc_attr_parsing::DefaultBodyStability,
-    rustc_attr_parsing::Deprecation,
-    rustc_attr_parsing::Stability,
+    rustc_attr_data_structures::ConstStability,
+    rustc_attr_data_structures::DefaultBodyStability,
+    rustc_attr_data_structures::Deprecation,
+    rustc_attr_data_structures::Stability,
     rustc_hir::Constness,
     rustc_hir::Defaultness,
     rustc_hir::Safety,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 34d85534d0a..2a3a7705b7b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -569,7 +569,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             // the children of the visible parent (as was done when computing
             // `visible_parent_map`), looking for the specific child we currently have and then
             // have access to the re-exported name.
-            DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {
+            DefPathData::TypeNs(Some(ref mut name)) if Some(visible_parent) != actual_parent => {
                 // Item might be re-exported several times, but filter for the one
                 // that's public and whose identifier isn't `_`.
                 let reexport = self
@@ -590,7 +590,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             }
             // Re-exported `extern crate` (#43189).
             DefPathData::CrateRoot => {
-                data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
+                data = DefPathData::TypeNs(Some(self.tcx().crate_name(def_id.krate)));
             }
             _ => {}
         }
diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
index 7f0d82d89fe..2d9e0331451 100644
--- a/compiler/rustc_middle/src/ty/significant_drop_order.rs
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -23,9 +23,11 @@ fn true_significant_drop_ty<'tcx>(
 
             match key.disambiguated_data.data {
                 rustc_hir::definitions::DefPathData::CrateRoot => {
-                    name_rev.push(tcx.crate_name(did.krate))
+                    name_rev.push(tcx.crate_name(did.krate));
+                }
+                rustc_hir::definitions::DefPathData::TypeNs(symbol) => {
+                    name_rev.push(symbol.unwrap());
                 }
-                rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
                 _ => return None,
             }
             if let Some(parent) = key.parent {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 237aa66f486..0c68913904f 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> {
         ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
     }
 
+    /// Checks whether `ty: UseCloned` holds while ignoring region constraints.
+    ///
+    /// This function should not be used if there is an `InferCtxt` available.
+    /// Use `InferCtxt::type_is_copy_modulo_regions` instead.
+    pub fn type_is_use_cloned_modulo_regions(
+        self,
+        typing_env: ty::TypingEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty))
+    }
+
     /// Returns the deeply last field of nested structures, or the same type if
     /// not a structure at all. Corresponds to the only possible unsized field,
     /// and its type can be used to determine unsizing strategy.
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
index 581f45db6c4..50ca924baf9 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
@@ -582,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Yield { .. }
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::Call { .. }
+            | ExprKind::ByUse { .. }
             | ExprKind::WrapUnsafeBinder { .. } => {
                 // these are not places, so we need to make a temporary.
                 debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
index 2c9a1de7f99..97d34b85f50 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
@@ -572,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 block.and(Rvalue::Use(operand))
             }
+
+            ExprKind::ByUse { expr, span: _ } => {
+                let operand = unpack!(
+                    block =
+                        this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
+                );
+                block.and(Rvalue::Use(operand))
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs
index ca55d36bfc6..34524aed406 100644
--- a/compiler/rustc_mir_build/src/builder/expr/category.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/category.rs
@@ -56,6 +56,7 @@ impl Category {
             | ExprKind::RawBorrow { .. }
             | ExprKind::Yield { .. }
             | ExprKind::Call { .. }
+            | ExprKind::ByUse { .. }
             | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
 
             ExprKind::Array { .. }
diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs
index 72443e2f60d..333e69475c5 100644
--- a/compiler/rustc_mir_build/src/builder/expr/into.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/into.rs
@@ -4,11 +4,14 @@ use rustc_ast::{AsmMacro, InlineAsmOptions};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::thir::*;
-use rustc_middle::ty::CanonicalUserTypeAnnotation;
+use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
+use rustc_span::DUMMY_SP;
 use rustc_span::source_map::Spanned;
+use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::{debug, instrument};
 
 use crate::builder::expr::category::{Category, RvalueFunc};
@@ -289,6 +292,57 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.diverge_from(block);
                 success.unit()
             }
+            ExprKind::ByUse { expr, span } => {
+                let place = unpack!(block = this.as_place(block, expr));
+                let ty = place.ty(&this.local_decls, this.tcx).ty;
+
+                if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) {
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        destination,
+                        Rvalue::Use(Operand::Copy(place)),
+                    );
+                    block.unit()
+                } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) {
+                    // Convert `expr.use` to a call like `Clone::clone(&expr)`
+                    let success = this.cfg.start_new_block();
+                    let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
+                    let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
+                    let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
+                    let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
+                    let ref_place = this.temp(ref_ty, span);
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        ref_place,
+                        Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
+                    );
+                    this.cfg.terminate(
+                        block,
+                        source_info,
+                        TerminatorKind::Call {
+                            func,
+                            args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }]
+                                .into(),
+                            destination,
+                            target: Some(success),
+                            unwind: UnwindAction::Unreachable,
+                            call_source: CallSource::Misc,
+                            fn_span: expr_span,
+                        },
+                    );
+                    success.unit()
+                } else {
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        destination,
+                        Rvalue::Use(Operand::Move(place)),
+                    );
+                    block.unit()
+                }
+            }
             ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
             ExprKind::Borrow { arg, borrow_kind } => {
                 // We don't do this in `as_rvalue` because we use `as_place`
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 94955954934..f9fa750e750 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
         .map(|captured_place| {
             let name = captured_place.to_symbol();
             match captured_place.info.capture_kind {
-                ty::UpvarCapture::ByValue => name,
+                ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name,
                 ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
             }
         })
@@ -612,7 +612,8 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -
         | DefKind::AssocConst
         | DefKind::AnonConst
         | DefKind::InlineConst
-        | DefKind::Static { .. } => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
+        | DefKind::Static { .. }
+        | DefKind::GlobalAsm => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
         DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => {
             let sig = tcx.liberate_late_bound_regions(
                 def_id.to_def_id(),
@@ -871,7 +872,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let mut projs = closure_env_projs.clone();
                 projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
                 match capture {
-                    ty::UpvarCapture::ByValue => {}
+                    ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
                     ty::UpvarCapture::ByRef(..) => {
                         projs.push(ProjectionElem::Deref);
                     }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index c2eafd0a74e..d78c874c766 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -451,6 +451,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             | ExprKind::Tuple { .. }
             | ExprKind::Unary { .. }
             | ExprKind::Call { .. }
+            | ExprKind::ByUse { .. }
             | ExprKind::Assign { .. }
             | ExprKind::AssignOp { .. }
             | ExprKind::Break { .. }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 7139516702e..e46e8c9871a 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -464,6 +464,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 }
             }
 
+            hir::ExprKind::Use(expr, span) => {
+                ExprKind::ByUse { expr: self.mirror_expr(expr), span }
+            }
+
             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => {
                 ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
             }
@@ -648,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 }
             },
 
-            hir::ExprKind::Closure { .. } => {
+            hir::ExprKind::Closure(hir::Closure { .. }) => {
                 let closure_ty = self.typeck_results.expr_ty(expr);
                 let (def_id, args, movability) = match *closure_ty.kind() {
                     ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
@@ -1248,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> {
 
         match upvar_capture {
             ty::UpvarCapture::ByValue => captured_place_expr,
+            ty::UpvarCapture::ByUse => {
+                let span = captured_place_expr.span;
+                let expr_id = self.thir.exprs.push(captured_place_expr);
+
+                Expr {
+                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                    ty: upvar_ty,
+                    span: closure_expr.span,
+                    kind: ExprKind::ByUse { expr: expr_id, span },
+                }
+            }
             ty::UpvarCapture::ByRef(upvar_borrow) => {
                 let borrow_kind = match upvar_borrow {
                     ty::BorrowKind::Immutable => BorrowKind::Shared,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 954d0cf97ab..dadd1e85461 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             | Borrow { .. }
             | Box { .. }
             | Call { .. }
+            | ByUse { .. }
             | Closure { .. }
             | ConstBlock { .. }
             | ConstParam { .. }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index cd56d93afcf..16cef0ec3ac 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -246,6 +246,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
 
                 print_indented!(self, "}", depth_lvl);
             }
+            ByUse { expr, span } => {
+                print_indented!(self, "ByUse {", depth_lvl);
+                print_indented!(self, "expr:", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
             Deref { arg } => {
                 print_indented!(self, "Deref {", depth_lvl);
                 self.print_expr(*arg, depth_lvl + 1);
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index 55694cacd92..bc335cee147 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -40,6 +40,16 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
         let mut new_blocks = Vec::new();
 
         let cur_len = body.basic_blocks.len();
+        let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| {
+            let block = BasicBlockData {
+                statements: vec![],
+                is_cleanup,
+                terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
+            };
+            let idx = cur_len + new_blocks.len();
+            new_blocks.push(block);
+            BasicBlock::new(idx)
+        };
 
         for block in body.basic_blocks_mut() {
             match block.terminator {
@@ -47,25 +57,34 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
                     kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. },
                     source_info,
                 }) if pred_count[*destination] > 1
-                    && (matches!(
-                        unwind,
-                        UnwindAction::Cleanup(_) | UnwindAction::Terminate(_)
-                    ) || self == &AllCallEdges) =>
+                    && (generates_invoke(unwind) || self == &AllCallEdges) =>
                 {
                     // It's a critical edge, break it
-                    let call_guard = BasicBlockData {
-                        statements: vec![],
-                        is_cleanup: block.is_cleanup,
-                        terminator: Some(Terminator {
-                            source_info,
-                            kind: TerminatorKind::Goto { target: *destination },
-                        }),
-                    };
-
-                    // Get the index it will be when inserted into the MIR
-                    let idx = cur_len + new_blocks.len();
-                    new_blocks.push(call_guard);
-                    *destination = BasicBlock::new(idx);
+                    *destination = new_block(source_info, block.is_cleanup, *destination);
+                }
+                Some(Terminator {
+                    kind:
+                        TerminatorKind::InlineAsm {
+                            asm_macro: InlineAsmMacro::Asm,
+                            ref mut targets,
+                            ref operands,
+                            unwind,
+                            ..
+                        },
+                    source_info,
+                }) if self == &CriticalCallEdges => {
+                    let has_outputs = operands.iter().any(|op| {
+                        matches!(op, InlineAsmOperand::InOut { .. } | InlineAsmOperand::Out { .. })
+                    });
+                    let has_labels =
+                        operands.iter().any(|op| matches!(op, InlineAsmOperand::Label { .. }));
+                    if has_outputs && (has_labels || generates_invoke(unwind)) {
+                        for target in targets.iter_mut() {
+                            if pred_count[*target] > 1 {
+                                *target = new_block(source_info, block.is_cleanup, *target);
+                            }
+                        }
+                    }
                 }
                 _ => {}
             }
@@ -80,3 +99,11 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
         true
     }
 }
+
+/// Returns true if this unwind action is code generated as an invoke as opposed to a call.
+fn generates_invoke(unwind: UnwindAction) -> bool {
+    match unwind {
+        UnwindAction::Continue | UnwindAction::Unreachable => false,
+        UnwindAction::Cleanup(_) | UnwindAction::Terminate(_) => true,
+    }
+}
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 0f5fcb0d8eb..9cd7045a0a2 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -78,7 +78,6 @@ use rustc_middle::hir::place::{Projection, ProjectionKind};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir};
 use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::kw;
 
 pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -170,7 +169,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
             // this when building the field projection in the MIR body later on.
             let mut parent_capture_ty = parent_capture.place.ty();
             parent_capture_ty = match parent_capture.info.capture_kind {
-                ty::UpvarCapture::ByValue => parent_capture_ty,
+                ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty,
                 ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
                     tcx,
                     tcx.lifetimes.re_erased,
@@ -214,7 +213,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
     MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
 
     // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`.
-    let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody);
+    let body_def = tcx.create_def(parent_def_id, None, DefKind::SyntheticCoroutineBody);
     by_move_body.source =
         mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id()));
     dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(()));
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 31f78bcf40a..f84b3b36ab3 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -317,6 +317,10 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
     // All body-owners have MIR associated with them.
     let mut set: FxIndexSet<_> = tcx.hir_body_owners().collect();
 
+    // Remove the fake bodies for `global_asm!`, since they're not useful
+    // to be emitted (`--emit=mir`) or encoded (in metadata).
+    set.retain(|&def_id| !matches!(tcx.def_kind(def_id), DefKind::GlobalAsm));
+
     // Coroutine-closures (e.g. async closures) have an additional by-move MIR
     // body that isn't in the HIR.
     for body_owner in tcx.hir_body_owners() {
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 1d5b5942170..6d4308cda1a 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -26,6 +26,11 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
     .suggestion = try switching the order
 
+parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later
+
+parse_async_use_order_incorrect = the order of `use` and `async` is incorrect
+    .suggestion = try switching the order
+
 parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
     .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
 
@@ -348,6 +353,9 @@ parse_incorrect_use_of_await = incorrect use of `await`
 
 parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation
 
+parse_incorrect_use_of_use = incorrect use of `use`
+    .parentheses_suggestion = `use` is not a method call, try removing the parentheses
+
 parse_incorrect_visibility_restriction = incorrect visibility restriction
     .help = some possible visibility restrictions are:
             `pub(crate)`: visible only on the current crate
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 8d2fd595942..e090d9cf760 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -106,6 +106,19 @@ pub(crate) struct IncorrectUseOfAwait {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_incorrect_use_of_use)]
+pub(crate) struct IncorrectUseOfUse {
+    #[primary_span]
+    #[suggestion(
+        parse_parentheses_suggestion,
+        style = "verbose",
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(
     parse_incorrect_use_of_await_postfix_suggestion,
@@ -1500,6 +1513,14 @@ pub(crate) struct AsyncMoveOrderIncorrect {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_async_use_order_incorrect)]
+pub(crate) struct AsyncUseOrderIncorrect {
+    #[primary_span]
+    #[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_double_colon_in_bound)]
 pub(crate) struct DoubleColonInBound {
     #[primary_span]
@@ -1668,6 +1689,13 @@ pub(crate) struct AsyncMoveBlockIn2015 {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_async_use_block_in_2015)]
+pub(crate) struct AsyncUseBlockIn2015 {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_async_bound_modifier_in_2015)]
 pub(crate) struct AsyncBoundModifierIn2015 {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 94db43bb59f..bb227a58cf1 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -31,15 +31,15 @@ use super::{
     SeqSep, TokenType,
 };
 use crate::errors::{
-    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
-    BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
-    ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
-    ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
-    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
+    AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
+    ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
+    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
+    DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
     GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
     HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
-    IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
-    QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+    IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
+    QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
     StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
     SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
     UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
@@ -572,10 +572,17 @@ impl<'a> Parser<'a> {
             return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
         }
 
-        if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
-            // The 2015 edition is in use because parsing of `async move` has failed.
+        if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use))
+            && self.prev_token.is_keyword(kw::Async)
+        {
+            // The 2015 edition is in use because parsing of `async move` or `async use` has failed.
             let span = self.prev_token.span.to(self.token.span);
-            return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
+            if self.token.is_keyword(kw::Move) {
+                return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
+            } else {
+                // kw::Use
+                return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span }));
+            }
         }
 
         let expect = tokens_to_string(&expected);
@@ -1991,7 +1998,7 @@ impl<'a> Parser<'a> {
             self.parse_expr()
         }
         .map_err(|mut err| {
-            err.span_label(await_sp, "while parsing this incorrect await expression");
+            err.span_label(await_sp, format!("while parsing this incorrect await expression"));
             err
         })?;
         Ok((expr.span, expr, is_question))
@@ -2030,6 +2037,21 @@ impl<'a> Parser<'a> {
             self.dcx().emit_err(IncorrectUseOfAwait { span });
         }
     }
+    ///
+    /// If encountering `x.use()`, consumes and emits an error.
+    pub(super) fn recover_from_use(&mut self) {
+        if self.token == token::OpenDelim(Delimiter::Parenthesis)
+            && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
+        {
+            // var.use()
+            let lo = self.token.span;
+            self.bump(); // (
+            let span = lo.to(self.token.span);
+            self.bump(); // )
+
+            self.dcx().emit_err(IncorrectUseOfUse { span });
+        }
+    }
 
     pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
         let is_try = self.token.is_keyword(kw::Try);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index cab0c7df3e0..9b2d562a69e 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -778,6 +778,7 @@ impl<'a> Parser<'a> {
                     ExprKind::MethodCall(_) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_, _) => "`.await`",
+                    ExprKind::Use(_, _) => "`.use`",
                     ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
                     ExprKind::Err(_) => return Ok(with_postfix),
                     _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
@@ -1296,6 +1297,12 @@ impl<'a> Parser<'a> {
             return Ok(self.mk_await_expr(self_arg, lo));
         }
 
+        if self.eat_keyword(exp!(Use)) {
+            let use_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
+            return Ok(self.mk_use_expr(self_arg, lo));
+        }
+
         // Post-fix match
         if self.eat_keyword(exp!(Match)) {
             let match_span = self.prev_token.span;
@@ -1396,6 +1403,7 @@ impl<'a> Parser<'a> {
             } else if this.check_path() {
                 this.parse_expr_path_start()
             } else if this.check_keyword(exp!(Move))
+                || this.check_keyword(exp!(Use))
                 || this.check_keyword(exp!(Static))
                 || this.check_const_closure()
             {
@@ -2387,7 +2395,7 @@ impl<'a> Parser<'a> {
         Ok(closure)
     }
 
-    /// Parses an optional `move` prefix to a closure-like construct.
+    /// Parses an optional `move` or `use` prefix to a closure-like construct.
     fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
         if self.eat_keyword(exp!(Move)) {
             let move_kw_span = self.prev_token.span;
@@ -2400,6 +2408,16 @@ impl<'a> Parser<'a> {
             } else {
                 Ok(CaptureBy::Value { move_kw: move_kw_span })
             }
+        } else if self.eat_keyword(exp!(Use)) {
+            let use_kw_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
+            // Check for `use async` and recover
+            if self.check_keyword(exp!(Async)) {
+                let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
+                Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
+            } else {
+                Ok(CaptureBy::Use { use_kw: use_kw_span })
+            }
         } else {
             Ok(CaptureBy::Ref)
         }
@@ -3414,7 +3432,7 @@ impl<'a> Parser<'a> {
         self.is_keyword_ahead(lookahead, &[kw])
             && ((
                 // `async move {`
-                self.is_keyword_ahead(lookahead + 1, &[kw::Move])
+                self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
                     && self.look_ahead(lookahead + 2, |t| {
                         *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
                     })
@@ -3817,6 +3835,13 @@ impl<'a> Parser<'a> {
         await_expr
     }
 
+    fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
+        let span = lo.to(self.prev_token.span);
+        let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
+        self.recover_from_use();
+        use_expr
+    }
+
     pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
         P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
     }
@@ -3965,6 +3990,7 @@ impl MutVisitor for CondChecker<'_> {
             }
             ExprKind::Unary(_, _)
             | ExprKind::Await(_, _)
+            | ExprKind::Use(_, _)
             | ExprKind::AssignOp(_, _, _)
             | ExprKind::Range(_, _, _)
             | ExprKind::Try(_)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 5d537a0e144..dc6b426f514 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -212,7 +212,7 @@ impl<'a> Parser<'a> {
         let check_pub = def == &Defaultness::Final;
         let mut def_ = || mem::replace(def, Defaultness::Final);
 
-        let info = if self.eat_keyword_case(exp!(Use), case) {
+        let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
             self.parse_use_item()?
         } else if self.check_fn_front_matter(check_pub, case) {
             // FUNCTION ITEM
@@ -1280,6 +1280,21 @@ impl<'a> Parser<'a> {
         None
     }
 
+    fn is_use_closure(&self) -> bool {
+        if self.token.is_keyword(kw::Use) {
+            // Check if this could be a closure.
+            self.look_ahead(1, |token| {
+                // Move or Async here would be an error but still we're parsing a closure
+                let dist =
+                    if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 };
+
+                self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr))
+            })
+        } else {
+            false
+        }
+    }
+
     fn is_unsafe_foreign_mod(&self) -> bool {
         self.token.is_keyword(kw::Unsafe)
             && self.is_keyword_ahead(1, &[kw::Extern])
@@ -1293,7 +1308,7 @@ impl<'a> Parser<'a> {
         if self.check_keyword(exp!(Static)) {
             // Check if this could be a closure.
             !self.look_ahead(1, |token| {
-                if token.is_keyword(kw::Move) {
+                if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
                     return true;
                 }
                 matches!(token.kind, token::Or | token::OrOr)
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 0bb6e2ab126..323c0c1d6d0 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -813,9 +813,9 @@ impl<'a> Parser<'a> {
         self.is_keyword_ahead(0, &[kw::Const])
             && self.look_ahead(1, |t| match &t.kind {
                 // async closures do not work with const closures, so we do not parse that here.
-                token::Ident(kw::Move | kw::Static, IdentIsRaw::No) | token::OrOr | token::Or => {
-                    true
-                }
+                token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No)
+                | token::OrOr
+                | token::Or => true,
                 _ => false,
             })
     }
diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs
index 110546d0ba6..886438fd583 100644
--- a/compiler/rustc_parse/src/parser/token_type.rs
+++ b/compiler/rustc_parse/src/parser/token_type.rs
@@ -619,7 +619,7 @@ impl Iterator for TokenTypeSetIter {
     type Item = TokenType;
 
     fn next(&mut self) -> Option<TokenType> {
-        let num_bits: u32 = (std::mem::size_of_val(&self.0.0) * 8) as u32;
+        let num_bits: u32 = (size_of_val(&self.0.0) * 8) as u32;
         assert_eq!(num_bits, 128);
         let z = self.0.0.trailing_zeros();
         if z == num_bits {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 91916b8f5fc..c6ae2c0fb9b 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1998,7 +1998,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`)
                     if item.is_some() {
                         match target {
-                            Target::Struct | Target::Union | Target::Enum => {}
+                            Target::Struct | Target::Union | Target::Enum => continue,
                             Target::Fn | Target::Method(_) => {
                                 feature_err(
                                     &self.tcx.sess,
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 92ea49f18e5..1278e98afcf 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -107,12 +107,12 @@ impl<'k> StatCollector<'k> {
 
         let node = self.nodes.entry(label1).or_insert(Node::new());
         node.stats.count += 1;
-        node.stats.size = std::mem::size_of_val(val);
+        node.stats.size = size_of_val(val);
 
         if let Some(label2) = label2 {
             let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new());
             subnode.count += 1;
-            subnode.size = std::mem::size_of_val(val);
+            subnode.size = size_of_val(val);
         }
     }
 
@@ -255,9 +255,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_body(self, b);
     }
 
-    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) {
+    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) {
         self.record("Mod", None, m);
-        hir_visit::walk_mod(self, m, n)
+        hir_visit::walk_mod(self, m)
     }
 
     fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
@@ -328,6 +328,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 Array,
                 Call,
                 MethodCall,
+                Use,
                 Tup,
                 Binary,
                 Unary,
@@ -626,7 +627,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
             (self, e, e.kind, None, ast, Expr, ExprKind),
             [
                 Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
-                If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
+                If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
                 InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
                 Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 24dc018c661..822804893fe 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -426,6 +426,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             | hir::ExprKind::Array(..)
             | hir::ExprKind::Call(..)
             | hir::ExprKind::MethodCall(..)
+            | hir::ExprKind::Use(..)
             | hir::ExprKind::Tup(..)
             | hir::ExprKind::Binary(..)
             | hir::ExprKind::AddrOf(..)
@@ -705,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                             );
                             self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
                         }
-                        ty::UpvarCapture::ByValue => {}
+                        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
                     }
                 }
             }
@@ -1031,6 +1032,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.propagate_through_expr(receiver, succ)
             }
 
+            hir::ExprKind::Use(expr, _) => {
+                let succ = self.check_is_ty_uninhabited(expr, succ);
+                self.propagate_through_expr(expr, succ)
+            }
+
             hir::ExprKind::Tup(exprs) => self.propagate_through_exprs(exprs, succ),
 
             hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
@@ -1418,6 +1424,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         // no correctness conditions related to liveness
         hir::ExprKind::Call(..)
         | hir::ExprKind::MethodCall(..)
+        | hir::ExprKind::Use(..)
         | hir::ExprKind::Match(..)
         | hir::ExprKind::Loop(..)
         | hir::ExprKind::Index(..)
@@ -1493,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
         for (&var_hir_id, min_capture_list) in closure_min_captures {
             for captured_place in min_capture_list {
                 match captured_place.info.capture_kind {
-                    ty::UpvarCapture::ByValue => {}
+                    ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
                     ty::UpvarCapture::ByRef(..) => continue,
                 };
                 let span = captured_place.get_capture_kind_span(self.ir.tcx);
diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs
index 6e2f976e5b0..4c1f6ea141e 100644
--- a/compiler/rustc_passes/src/liveness/rwu_table.rs
+++ b/compiler/rustc_passes/src/liveness/rwu_table.rs
@@ -39,7 +39,7 @@ impl RWUTable {
     /// Size of packed RWU in bits.
     const RWU_BITS: usize = 4;
     /// Size of a word in bits.
-    const WORD_BITS: usize = std::mem::size_of::<u8>() * 8;
+    const WORD_BITS: usize = size_of::<u8>() * 8;
     /// Number of packed RWUs that fit into a single word.
     const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS;
 
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index cb17b0f6cf5..d35aedf9a56 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -182,6 +182,7 @@ impl CheckInlineAssembly {
             | ExprKind::Array(..)
             | ExprKind::Call(..)
             | ExprKind::MethodCall(..)
+            | ExprKind::Use(..)
             | ExprKind::Tup(..)
             | ExprKind::Binary(..)
             | ExprKind::Unary(..)
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 5e6bee1dbd5..6ece01c211b 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1299,12 +1299,11 @@ impl Default for TaskDeps {
             #[cfg(debug_assertions)]
             node: None,
             reads: EdgesVec::new(),
-            read_set: FxHashSet::default(),
+            read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()),
             phantom_data: PhantomData,
         }
     }
 }
-
 // A data structure that stores Option<DepNodeColor> values as a contiguous
 // array, using one u32 per entry.
 struct DepNodeColorMap {
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index bc78878a84a..2c6fd7d494f 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -63,7 +63,7 @@ rustc_index::newtype_index! {
     pub struct SerializedDepNodeIndex {}
 }
 
-const DEP_NODE_SIZE: usize = std::mem::size_of::<SerializedDepNodeIndex>();
+const DEP_NODE_SIZE: usize = size_of::<SerializedDepNodeIndex>();
 /// Amount of padding we need to add to the edge list data so that we can retrieve every
 /// SerializedDepNodeIndex with a fixed-size read then mask.
 const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
@@ -175,7 +175,7 @@ impl EdgeHeader {
 
 #[inline]
 fn mask(bits: usize) -> usize {
-    usize::MAX >> ((std::mem::size_of::<usize>() * 8) - bits)
+    usize::MAX >> ((size_of::<usize>() * 8) - bits)
 }
 
 impl SerializedDepGraph {
@@ -208,9 +208,8 @@ impl SerializedDepGraph {
         // for a node with length 64, which means the spilled 1-byte leb128 length is 1 byte of at
         // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128
         // length is about the same fractional overhead and it amortizes for yet greater lengths.
-        let mut edge_list_data = Vec::with_capacity(
-            graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<D>>(),
-        );
+        let mut edge_list_data =
+            Vec::with_capacity(graph_bytes - node_count * size_of::<SerializedNodeHeader<D>>());
 
         for _index in 0..node_count {
             // Decode the header for this edge; the header packs together as many of the fixed-size
@@ -300,7 +299,7 @@ struct Unpacked {
 // M..M+N  bytes per index
 // M+N..16 kind
 impl<D: Deps> SerializedNodeHeader<D> {
-    const TOTAL_BITS: usize = std::mem::size_of::<DepKind>() * 8;
+    const TOTAL_BITS: usize = size_of::<DepKind>() * 8;
     const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS;
     const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS;
     const KIND_BITS: usize = Self::TOTAL_BITS - D::DEP_KIND_MAX.leading_zeros() as usize;
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 95d637b6b22..33f529851ae 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -9,7 +9,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::LocalDefId;
 use rustc_span::hygiene::LocalExpnId;
-use rustc_span::{Span, Symbol, kw, sym};
+use rustc_span::{Span, Symbol, sym};
 use tracing::debug;
 
 use crate::{ImplTraitContext, InvocationParent, Resolver};
@@ -38,7 +38,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
     fn create_def(
         &mut self,
         node_id: NodeId,
-        name: Symbol,
+        name: Option<Symbol>,
         def_kind: DefKind,
         span: Span,
     ) -> LocalDefId {
@@ -89,7 +89,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
             self.visit_macro_invoc(field.id);
         } else {
             let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
-            let def = self.create_def(field.id, name, DefKind::Field, field.span);
+            let def = self.create_def(field.id, Some(name), DefKind::Field, field.span);
             self.with_parent(def, |this| visit::walk_field_def(this, field));
         }
     }
@@ -161,7 +161,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 return self.visit_macro_invoc(i.id);
             }
         };
-        let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
+        let def_id = self.create_def(i.id, Some(i.ident.name), def_kind, i.span);
 
         if let Some(macro_data) = opt_macro_data {
             self.resolver.macro_map.insert(def_id.to_def_id(), macro_data);
@@ -175,7 +175,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                         if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) {
                             this.create_def(
                                 ctor_node_id,
-                                kw::Empty,
+                                None,
                                 DefKind::Ctor(CtorOf::Struct, ctor_kind),
                                 i.span,
                             );
@@ -211,20 +211,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 }
 
                 let (return_id, return_span) = coroutine_kind.return_id();
-                let return_def =
-                    self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span);
+                let return_def = self.create_def(return_id, None, DefKind::OpaqueTy, return_span);
                 self.with_parent(return_def, |this| this.visit_fn_ret_ty(output));
 
                 // If this async fn has no body (i.e. it's an async fn signature in a trait)
                 // then the closure_def will never be used, and we should avoid generating a
                 // def-id for it.
                 if let Some(body) = body {
-                    let closure_def = self.create_def(
-                        coroutine_kind.closure_id(),
-                        kw::Empty,
-                        DefKind::Closure,
-                        span,
-                    );
+                    let closure_def =
+                        self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span);
                     self.with_parent(closure_def, |this| this.visit_block(body));
                 }
             }
@@ -235,7 +230,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 // Async closures desugar to closures inside of closures, so
                 // we must create two defs.
                 let coroutine_def =
-                    self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span);
+                    self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span);
                 self.with_parent(coroutine_def, |this| this.visit_expr(body));
             }
             _ => visit::walk_fn(self, fn_kind),
@@ -243,7 +238,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
     }
 
     fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
-        self.create_def(id, kw::Empty, DefKind::Use, use_tree.span);
+        self.create_def(id, None, DefKind::Use, use_tree.span);
         visit::walk_use_tree(self, use_tree, id);
     }
 
@@ -262,7 +257,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
             ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id),
         };
 
-        let def = self.create_def(fi.id, fi.ident.name, def_kind, fi.span);
+        let def = self.create_def(fi.id, Some(fi.ident.name), def_kind, fi.span);
 
         self.with_parent(def, |this| visit::walk_item(this, fi));
     }
@@ -271,12 +266,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
         if v.is_placeholder {
             return self.visit_macro_invoc(v.id);
         }
-        let def = self.create_def(v.id, v.ident.name, DefKind::Variant, v.span);
+        let def = self.create_def(v.id, Some(v.ident.name), DefKind::Variant, v.span);
         self.with_parent(def, |this| {
             if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) {
                 this.create_def(
                     ctor_node_id,
-                    kw::Empty,
+                    None,
                     DefKind::Ctor(CtorOf::Variant, ctor_kind),
                     v.span,
                 );
@@ -312,7 +307,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
             GenericParamKind::Type { .. } => DefKind::TyParam,
             GenericParamKind::Const { .. } => DefKind::ConstParam,
         };
-        self.create_def(param.id, param.ident.name, def_kind, param.ident.span);
+        self.create_def(param.id, Some(param.ident.name), def_kind, param.ident.span);
 
         // impl-Trait can happen inside generic parameters, like
         // ```
@@ -335,7 +330,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
             }
         };
 
-        let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
+        let def = self.create_def(i.id, Some(i.ident.name), def_kind, i.span);
         self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt));
     }
 
@@ -347,8 +342,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
     }
 
     fn visit_anon_const(&mut self, constant: &'a AnonConst) {
-        let parent =
-            self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
+        let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span);
         self.with_parent(parent, |this| visit::walk_anon_const(this, constant));
     }
 
@@ -356,18 +350,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
         let parent_def = match expr.kind {
             ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
             ExprKind::Closure(..) | ExprKind::Gen(..) => {
-                self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
+                self.create_def(expr.id, None, DefKind::Closure, expr.span)
             }
             ExprKind::ConstBlock(ref constant) => {
                 for attr in &expr.attrs {
                     visit::walk_attribute(self, attr);
                 }
-                let def = self.create_def(
-                    constant.id,
-                    kw::Empty,
-                    DefKind::InlineConst,
-                    constant.value.span,
-                );
+                let def =
+                    self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span);
                 self.with_parent(def, |this| visit::walk_anon_const(this, constant));
                 return;
             }
@@ -391,7 +381,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                     ImplTraitContext::Existential => DefKind::OpaqueTy,
                     ImplTraitContext::InBinding => return visit::walk_ty(self, ty),
                 };
-                let id = self.create_def(*id, name, kind, ty.span);
+                let id = self.create_def(*id, Some(name), kind, ty.span);
                 match self.impl_trait_context {
                     // Do not nest APIT, as we desugar them as `impl_trait: bounds`,
                     // so the `impl_trait` node is not a parent to `bounds`.
@@ -495,7 +485,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 InlineAsmOperand::Const { anon_const } => {
                     let def = self.create_def(
                         anon_const.id,
-                        kw::Empty,
+                        None,
                         DefKind::InlineConst,
                         anon_const.value.span,
                     );
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 92f5fba1f9b..79479986d07 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2995,7 +2995,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
     }
 
     // HACK(min_const_generics, generic_const_exprs): We
-    // want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
+    // want to keep allowing `[0; size_of::<*mut T>()]`
     // with a future compat lint for now. We do this by adding an
     // additional special case for repeat expressions.
     //
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 67024f988a4..84858cfc1b1 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -24,7 +24,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_hir::{MissingLifetimeKind, PrimTy};
 use rustc_middle::ty;
 use rustc_session::{Session, lint};
-use rustc_span::edit_distance::find_best_match_for_name;
+use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
@@ -2919,23 +2919,35 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             )
             .with_span_label(lifetime_ref.ident.span, "undeclared lifetime")
         };
-        self.suggest_introducing_lifetime(
-            &mut err,
-            Some(lifetime_ref.ident.name.as_str()),
-            |err, _, span, message, suggestion, span_suggs| {
-                err.multipart_suggestion_with_style(
-                    message,
-                    std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
-                    Applicability::MaybeIncorrect,
-                    if span_suggs.is_empty() {
-                        SuggestionStyle::ShowCode
-                    } else {
-                        SuggestionStyle::ShowAlways
-                    },
-                );
-                true
-            },
-        );
+
+        // Check if this is a typo of `'static`.
+        if edit_distance(lifetime_ref.ident.name.as_str(), "'static", 2).is_some() {
+            err.span_suggestion_verbose(
+                lifetime_ref.ident.span,
+                "you may have misspelled the `'static` lifetime",
+                "'static",
+                Applicability::MachineApplicable,
+            );
+        } else {
+            self.suggest_introducing_lifetime(
+                &mut err,
+                Some(lifetime_ref.ident.name.as_str()),
+                |err, _, span, message, suggestion, span_suggs| {
+                    err.multipart_suggestion_with_style(
+                        message,
+                        std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
+                        Applicability::MaybeIncorrect,
+                        if span_suggs.is_empty() {
+                            SuggestionStyle::ShowCode
+                        } else {
+                            SuggestionStyle::ShowAlways
+                        },
+                    );
+                    true
+                },
+            );
+        }
+
         err.emit();
     }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 4c5d4041022..ccdca855232 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1340,7 +1340,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
         &mut self,
         parent: LocalDefId,
         node_id: ast::NodeId,
-        name: Symbol,
+        name: Option<Symbol>,
         def_kind: DefKind,
         expn_id: ExpnId,
         span: Span,
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index aa7c2858466..4a475805697 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -7,7 +7,7 @@ use crate::serialize::Decoder;
 /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type
 pub const fn max_leb128_len<T>() -> usize {
     // The longest LEB128 encoding for an integer uses 7 bits per byte.
-    (std::mem::size_of::<T>() * 8 + 6) / 7
+    (size_of::<T>() * 8 + 6) / 7
 }
 
 /// Returns the length of the longest LEB128 encoding of all supported integer types.
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e62a8fc0fc3..7af221c9607 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -681,10 +681,14 @@ impl OutputType {
 }
 
 /// The type of diagnostics output to generate.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
 pub enum ErrorOutputType {
     /// Output meant for the consumption of humans.
-    HumanReadable(HumanReadableErrorType, ColorConfig),
+    #[default]
+    HumanReadable {
+        kind: HumanReadableErrorType = HumanReadableErrorType::Default,
+        color_config: ColorConfig = ColorConfig::Auto,
+    },
     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
     Json {
         /// Render the JSON in a human readable way (with indents and newlines).
@@ -696,12 +700,6 @@ pub enum ErrorOutputType {
     },
 }
 
-impl Default for ErrorOutputType {
-    fn default() -> Self {
-        Self::HumanReadable(HumanReadableErrorType::Default, ColorConfig::Auto)
-    }
-}
-
 #[derive(Clone, Hash, Debug)]
 pub enum ResolveDocLinks {
     /// Do not resolve doc links.
@@ -898,18 +896,13 @@ pub enum PrintKind {
     DeploymentTarget,
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
 pub struct NextSolverConfig {
     /// Whether the new trait solver should be enabled in coherence.
-    pub coherence: bool,
+    pub coherence: bool = true,
     /// Whether the new trait solver should be enabled everywhere.
     /// This is only `true` if `coherence` is also enabled.
-    pub globally: bool,
-}
-impl Default for NextSolverConfig {
-    fn default() -> Self {
-        NextSolverConfig { coherence: true, globally: false }
-    }
+    pub globally: bool = false,
 }
 
 #[derive(Clone)]
@@ -1825,7 +1818,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
 pub fn parse_error_format(
     early_dcx: &mut EarlyDiagCtxt,
     matches: &getopts::Matches,
-    color: ColorConfig,
+    color_config: ColorConfig,
     json_color: ColorConfig,
     json_rendered: HumanReadableErrorType,
 ) -> ErrorOutputType {
@@ -1835,27 +1828,26 @@ pub fn parse_error_format(
     // `opt_present` because the latter will panic.
     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
         match matches.opt_str("error-format").as_deref() {
-            None | Some("human") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color)
-            }
-            Some("human-annotate-rs") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, color)
-            }
+            None | Some("human") => ErrorOutputType::HumanReadable { color_config, .. },
+            Some("human-annotate-rs") => ErrorOutputType::HumanReadable {
+                kind: HumanReadableErrorType::AnnotateSnippet,
+                color_config,
+            },
             Some("json") => {
                 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
             }
             Some("pretty-json") => {
                 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
             }
-            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short, color),
-            Some("human-unicode") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, color)
+            Some("short") => {
+                ErrorOutputType::HumanReadable { kind: HumanReadableErrorType::Short, color_config }
             }
+            Some("human-unicode") => ErrorOutputType::HumanReadable {
+                kind: HumanReadableErrorType::Unicode,
+                color_config,
+            },
             Some(arg) => {
-                early_dcx.set_error_format(ErrorOutputType::HumanReadable(
-                    HumanReadableErrorType::Default,
-                    color,
-                ));
+                early_dcx.set_error_format(ErrorOutputType::HumanReadable { color_config, .. });
                 early_dcx.early_fatal(format!(
                     "argument for `--error-format` must be `human`, `human-annotate-rs`, \
                     `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
@@ -1863,7 +1855,7 @@ pub fn parse_error_format(
             }
         }
     } else {
-        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color)
+        ErrorOutputType::HumanReadable { color_config, .. }
     };
 
     match error_format {
@@ -1918,7 +1910,7 @@ fn check_error_format_stability(
     }
     let format = match format {
         ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
-        ErrorOutputType::HumanReadable(format, _) => match format {
+        ErrorOutputType::HumanReadable { kind, .. } => match kind {
             HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs",
             HumanReadableErrorType::Unicode => "human-unicode",
             _ => return,
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index ec83761da4a..cc2decc2fe4 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -92,7 +92,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
             if libc::loadquery(
                 libc::L_GETINFO,
                 buffer.as_mut_ptr() as *mut u8,
-                (std::mem::size_of::<libc::ld_info>() * buffer.len()) as u32,
+                (size_of::<libc::ld_info>() * buffer.len()) as u32,
             ) >= 0
             {
                 break;
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 112adde3740..d432e84fdb2 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,5 +1,6 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
+#![feature(default_field_values)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(rustc_attrs)]
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index ecdf76d22fb..bcd9a73d9d3 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -913,7 +913,7 @@ fn default_emitter(
     let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) };
 
     match sopts.error_format {
-        config::ErrorOutputType::HumanReadable(kind, color_config) => {
+        config::ErrorOutputType::HumanReadable { kind, color_config } => {
             let short = kind.short();
 
             if let HumanReadableErrorType::AnnotateSnippet = kind {
@@ -930,7 +930,6 @@ fn default_emitter(
                     .fluent_bundle(bundle)
                     .sm(source_map)
                     .short_message(short)
-                    .teach(sopts.unstable_opts.teach)
                     .diagnostic_width(sopts.diagnostic_width)
                     .macro_backtrace(macro_backtrace)
                     .track_diagnostics(track_diagnostics)
@@ -1430,7 +1429,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
     let fallback_bundle =
         fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
     let emitter: Box<DynEmitter> = match output {
-        config::ErrorOutputType::HumanReadable(kind, color_config) => {
+        config::ErrorOutputType::HumanReadable { kind, color_config } => {
             let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index 36f9b4cff60..da298080ed2 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -23,11 +23,27 @@ pub enum Edition {
     Edition2021,
     /// The 2024 edition
     Edition2024,
+    /// The future edition - this variant will always exist and features associated with this
+    /// edition can be moved to the next 20XX edition when it is established and it is confirmed
+    /// that those features will be part of that edition.
+    ///
+    /// This variant allows edition changes to be implemented before being assigned to a concrete
+    /// edition - primarily when there are two different unstable behaviours that need tested across
+    /// an edition boundary.
+    ///
+    /// This edition will be permanently unstable and any features associated with this edition
+    /// must also be behind a feature gate.
+    EditionFuture,
 }
 
 // Must be in order from oldest to newest.
-pub const ALL_EDITIONS: &[Edition] =
-    &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024];
+pub const ALL_EDITIONS: &[Edition] = &[
+    Edition::Edition2015,
+    Edition::Edition2018,
+    Edition::Edition2021,
+    Edition::Edition2024,
+    Edition::EditionFuture,
+];
 
 pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024";
 
@@ -42,6 +58,7 @@ impl fmt::Display for Edition {
             Edition::Edition2018 => "2018",
             Edition::Edition2021 => "2021",
             Edition::Edition2024 => "2024",
+            Edition::EditionFuture => "future",
         };
         write!(f, "{s}")
     }
@@ -54,6 +71,7 @@ impl Edition {
             Edition::Edition2018 => "rust_2018_compatibility",
             Edition::Edition2021 => "rust_2021_compatibility",
             Edition::Edition2024 => "rust_2024_compatibility",
+            Edition::EditionFuture => "edition_future_compatibility",
         }
     }
 
@@ -63,6 +81,7 @@ impl Edition {
             Edition::Edition2018 => true,
             Edition::Edition2021 => true,
             Edition::Edition2024 => true,
+            Edition::EditionFuture => false,
         }
     }
 
@@ -85,6 +104,11 @@ impl Edition {
     pub fn at_least_rust_2024(self) -> bool {
         self >= Edition::Edition2024
     }
+
+    /// Are we allowed to use features from the future edition?
+    pub fn at_least_edition_future(self) -> bool {
+        self >= Edition::EditionFuture
+    }
 }
 
 impl FromStr for Edition {
@@ -95,6 +119,7 @@ impl FromStr for Edition {
             "2018" => Ok(Edition::Edition2018),
             "2021" => Ok(Edition::Edition2021),
             "2024" => Ok(Edition::Edition2024),
+            "future" => Ok(Edition::EditionFuture),
             _ => Err(()),
         }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 573c65a772c..9e7f5047eb3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -862,6 +862,7 @@ symbols! {
         eprint_macro,
         eprintln_macro,
         eq,
+        ergonomic_clones,
         ermsb_target_feature,
         exact_div,
         except,
@@ -1717,6 +1718,7 @@ symbols! {
         rust_cold_cc,
         rust_eh_catch_typeinfo,
         rust_eh_personality,
+        rust_future,
         rust_logo,
         rust_out,
         rustc,
@@ -2185,6 +2187,7 @@ symbols! {
         unwrap,
         unwrap_binder,
         unwrap_or,
+        use_cloned,
         use_extern_macros,
         use_nested_groups,
         used,
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 198d08864be..6d0ee3c7ee5 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -31,6 +31,7 @@ mod sparc64;
 mod wasm;
 mod x86;
 mod x86_64;
+mod x86_win32;
 mod x86_win64;
 mod xtensa;
 
@@ -649,7 +650,11 @@ impl<'a, Ty> FnAbi<'a, Ty> {
                 };
                 let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
                 let opts = x86::X86Options { flavor, regparm, reg_struct_return };
-                x86::compute_abi_info(cx, self, opts);
+                if spec.is_like_msvc {
+                    x86_win32::compute_abi_info(cx, self, opts);
+                } else {
+                    x86::compute_abi_info(cx, self, opts);
+                }
             }
             "x86_64" => match abi {
                 ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index 73aff85a0ad..6f112b49400 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -36,7 +36,7 @@ where
             if t.abi_return_struct_as_int || opts.reg_struct_return {
                 // According to Clang, everyone but MSVC returns single-element
                 // float aggregates directly in a floating-point register.
-                if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {
+                if fn_abi.ret.layout.is_single_fp_element(cx) {
                     match fn_abi.ret.layout.size.bytes() {
                         4 => fn_abi.ret.cast_to(Reg::f32()),
                         8 => fn_abi.ret.cast_to(Reg::f64()),
@@ -64,31 +64,11 @@ where
             continue;
         }
 
-        // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
-        // See https://reviews.llvm.org/D72114 for Clang behavior
-
         let t = cx.target_spec();
         let align_4 = Align::from_bytes(4).unwrap();
         let align_16 = Align::from_bytes(16).unwrap();
 
-        if t.is_like_msvc
-            && arg.layout.is_adt()
-            && let Some(max_repr_align) = arg.layout.max_repr_align
-            && max_repr_align > align_4
-        {
-            // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
-            // Summarized here:
-            // - Arguments with _requested_ alignment > 4 are passed indirectly.
-            // - For backwards compatibility, arguments with natural alignment > 4 are still passed
-            //   on stack (via `byval`). For example, this includes `double`, `int64_t`,
-            //   and structs containing them, provided they lack an explicit alignment attribute.
-            assert!(
-                arg.layout.align.abi >= max_repr_align,
-                "abi alignment {:?} less than requested alignment {max_repr_align:?}",
-                arg.layout.align.abi,
-            );
-            arg.make_indirect();
-        } else if arg.layout.is_aggregate() {
+        if arg.layout.is_aggregate() {
             // We need to compute the alignment of the `byval` argument. The rules can be found in
             // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized
             // here, they are:
diff --git a/compiler/rustc_target/src/callconv/x86_win32.rs b/compiler/rustc_target/src/callconv/x86_win32.rs
new file mode 100644
index 00000000000..554a7368848
--- /dev/null
+++ b/compiler/rustc_target/src/callconv/x86_win32.rs
@@ -0,0 +1,81 @@
+use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface};
+
+use crate::callconv::FnAbi;
+use crate::spec::HasTargetSpec;
+
+pub(crate) fn compute_abi_info<'a, Ty, C>(
+    cx: &C,
+    fn_abi: &mut FnAbi<'a, Ty>,
+    opts: super::x86::X86Options,
+) where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout + HasTargetSpec,
+{
+    if !fn_abi.ret.is_ignore() {
+        if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() {
+            // Returning a structure. Most often, this will use
+            // a hidden first argument. On some platforms, though,
+            // small structs are returned as integers.
+            //
+            // Some links:
+            // https://www.angelcode.com/dev/callconv/callconv.html
+            // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
+            let t = cx.target_spec();
+            // MSVC does not special-case 1-element float aggregates, unlike others.
+            // GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed:
+            // - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
+            // - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667
+            if t.abi_return_struct_as_int || opts.reg_struct_return {
+                match fn_abi.ret.layout.size.bytes() {
+                    1 => fn_abi.ret.cast_to(Reg::i8()),
+                    2 => fn_abi.ret.cast_to(Reg::i16()),
+                    4 => fn_abi.ret.cast_to(Reg::i32()),
+                    8 => fn_abi.ret.cast_to(Reg::i64()),
+                    _ => fn_abi.ret.make_indirect(),
+                }
+            } else {
+                fn_abi.ret.make_indirect();
+            }
+        } else {
+            fn_abi.ret.extend_integer_width_to(32);
+        }
+    }
+
+    for arg in fn_abi.args.iter_mut() {
+        if arg.is_ignore() || !arg.layout.is_sized() {
+            continue;
+        }
+
+        // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
+        // See https://reviews.llvm.org/D72114 for Clang behavior
+
+        let align_4 = Align::from_bytes(4).unwrap();
+
+        if arg.layout.is_adt()
+            && let Some(max_repr_align) = arg.layout.max_repr_align
+            && max_repr_align > align_4
+        {
+            // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
+            // Summarized here:
+            // - Arguments with _requested_ alignment > 4 are passed indirectly.
+            // - For backwards compatibility, arguments with natural alignment > 4 are still passed
+            //   on stack (via `byval`). For example, this includes `double`, `int64_t`,
+            //   and structs containing them, provided they lack an explicit alignment attribute.
+            assert!(
+                arg.layout.align.abi >= max_repr_align,
+                "abi alignment {:?} less than requested alignment {max_repr_align:?}",
+                arg.layout.align.abi,
+            );
+            arg.make_indirect();
+        } else if arg.layout.is_aggregate() {
+            // Alignment of the `byval` argument.
+            // The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`.
+            let byval_align = align_4;
+            arg.pass_by_stack_offset(Some(byval_align));
+        } else {
+            arg.extend_integer_width_to(32);
+        }
+    }
+
+    super::x86::fill_inregs(cx, fn_abi, opts, false);
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 72202129f5b..15936c731ea 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1915,7 +1915,6 @@ supported_targets! {
     ("i686-pc-windows-msvc", i686_pc_windows_msvc),
     ("i686-uwp-windows-msvc", i686_uwp_windows_msvc),
     ("i686-win7-windows-msvc", i686_win7_windows_msvc),
-    ("i586-pc-windows-msvc", i586_pc_windows_msvc),
     ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc),
     ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc),
 
@@ -3503,7 +3502,15 @@ impl Target {
                     return load_file(&p);
                 }
 
-                Err(format!("Could not find specification for target {target_tuple:?}"))
+                // Leave in a specialized error message for the removed target.
+                // FIXME: If you see this and it's been a few months after this has been released,
+                // you can probably remove it.
+                if target_tuple == "i586-pc-windows-msvc" {
+                    Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead.\n\
+                        Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch".into())
+                } else {
+                    Err(format!("Could not find specification for target {target_tuple:?}"))
+                }
             }
             TargetTuple::TargetJson { ref contents, .. } => {
                 let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
deleted file mode 100644
index 394e6f9e6bf..00000000000
--- a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use crate::spec::Target;
-
-pub(crate) fn target() -> Target {
-    let mut base = super::i686_pc_windows_msvc::target();
-    base.rustc_abi = None; // overwrite the SSE2 ABI set by the base target
-    base.cpu = "pentium".into();
-    base.llvm_target = "i586-pc-windows-msvc".into();
-    base
-}
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
index dd98f34d323..cffdaa90727 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
@@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
             vendor: "espressif".into(),
 
             executables: true,
-            cpu: "esp32-s2".into(),
+            cpu: "esp32s2".into(),
             linker: Some("xtensa-esp32s2-elf-gcc".into()),
 
             // See https://github.com/espressif/rust-esp32-example/issues/3#issuecomment-861054477
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
index 29bcf12cbaf..7bf5834ab0a 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
 
         options: TargetOptions {
             vendor: "espressif".into(),
-            cpu: "esp32-s2".into(),
+            cpu: "esp32s2".into(),
             linker: Some("xtensa-esp32s2-elf-gcc".into()),
             max_atomic_width: Some(32),
             features: "+forced-atomics".into(),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
index dd6e7b6c3e8..2e4afc00541 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
@@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
             vendor: "espressif".into(),
 
             executables: true,
-            cpu: "esp32-s3".into(),
+            cpu: "esp32s3".into(),
             linker: Some("xtensa-esp32s3-elf-gcc".into()),
 
             // The esp32s3 only supports native 32bit atomics.
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
index ddc909f387e..d506888d8ee 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
 
         options: TargetOptions {
             vendor: "espressif".into(),
-            cpu: "esp32-s3".into(),
+            cpu: "esp32s3".into(),
             linker: Some("xtensa-esp32s3-elf-gcc".into()),
             max_atomic_width: Some(32),
             atomic_cas: true,
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index f373706b296..5cf0600ade8 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> {
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id)
     }
 
+    fn type_is_use_cloned_modulo_regions(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let ty = self.resolve_vars_if_possible(ty);
+        let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None);
+        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id)
+    }
+
     fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 75f53b063d1..39333082acd 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -2,7 +2,7 @@
 //!
 //! For concrete constants, this is fairly simple as we can just try and evaluate it.
 //!
-//! When dealing with polymorphic constants, for example `std::mem::size_of::<T>() - 1`,
+//! When dealing with polymorphic constants, for example `size_of::<T>() - 1`,
 //! this is not as easy.
 //!
 //! In this case we try to build an abstract representation of this constant using
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 77dbb43465e..0a54b8468fe 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1925,9 +1925,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let mut impl_candidate = None;
         for c in impls {
             if let Some(prev) = impl_candidate.replace(c) {
-                if self.prefer_lhs_over_victim(has_non_region_infer, c, prev) {
+                if self.prefer_lhs_over_victim(has_non_region_infer, c, prev.0) {
                     // Ok, prefer `c` over the previous entry
-                } else if self.prefer_lhs_over_victim(has_non_region_infer, prev, c) {
+                } else if self.prefer_lhs_over_victim(has_non_region_infer, prev, c.0) {
                     // Ok, keep `prev` instead of the new entry
                     impl_candidate = Some(prev);
                 } else {
@@ -1986,7 +1986,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         &self,
         has_non_region_infer: bool,
         (lhs, lhs_evaluation): (DefId, EvaluationResult),
-        (victim, victim_evaluation): (DefId, EvaluationResult),
+        victim: DefId,
     ) -> bool {
         let tcx = self.tcx();
         // See if we can toss out `victim` based on specialization.
@@ -2002,14 +2002,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         }
 
         match tcx.impls_are_allowed_to_overlap(lhs, victim) {
-            // For #33140 the impl headers must be exactly equal, the trait must not have
-            // any associated items and there are no where-clauses.
-            //
-            // We can just arbitrarily drop one of the impls.
-            Some(ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects) => {
-                assert_eq!(lhs_evaluation, victim_evaluation);
-                true
-            }
             // For candidates which already reference errors it doesn't really
             // matter what we do 🤷
             Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index cb3e81f5477..448ac558cad 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -20,7 +20,7 @@ use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
-use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
+use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
 use rustc_type_ir::solve::NoSolution;
 use specialization_graph::GraphExt;
@@ -557,13 +557,9 @@ fn report_conflicting_impls<'tcx>(
 
     let msg = || {
         format!(
-            "conflicting implementations of trait `{}`{}{}",
+            "conflicting implementations of trait `{}`{}",
             overlap.trait_ref.print_trait_sugared(),
             overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
-            match used_to_be_allowed {
-                Some(FutureCompatOverlapErrorKind::OrderDepTraitObjects) => ": (E0119)",
-                _ => "",
-            }
         )
     };
 
@@ -588,7 +584,6 @@ fn report_conflicting_impls<'tcx>(
         }
         Some(kind) => {
             let lint = match kind {
-                FutureCompatOverlapErrorKind::OrderDepTraitObjects => ORDER_DEPENDENT_TRAIT_OBJECTS,
                 FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
             };
             tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 19d3561dd59..9452dca9a4f 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -12,7 +12,6 @@ use crate::traits;
 
 #[derive(Copy, Clone, Debug)]
 pub enum FutureCompatOverlapErrorKind {
-    OrderDepTraitObjects,
     LeakCheck,
 }
 
@@ -151,12 +150,6 @@ impl<'tcx> Children {
                 {
                     match overlap_kind {
                         ty::ImplOverlapKind::Permitted { marker: _ } => {}
-                        ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects => {
-                            *last_lint_mut = Some(FutureCompatOverlapError {
-                                error: create_overlap_error(overlap),
-                                kind: FutureCompatOverlapErrorKind::OrderDepTraitObjects,
-                            });
-                        }
                     }
 
                     return Ok((false, false));
diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl
index de2c3b63997..8bc7bf10865 100644
--- a/compiler/rustc_ty_utils/messages.ftl
+++ b/compiler/rustc_ty_utils/messages.ftl
@@ -14,6 +14,8 @@ ty_utils_borrow_not_supported = borrowing is not supported in generic constants
 
 ty_utils_box_not_supported = allocations are not allowed in generic constants
 
+ty_utils_by_use_not_supported = .use is not allowed in generic constants
+
 ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
 
 ty_utils_const_block_not_supported = const blocks are not supported in generic constants
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index c8034f4e7b9..c84055f5b84 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -252,7 +252,8 @@ fn associated_type_for_impl_trait_in_trait(
     assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
 
     let span = tcx.def_span(opaque_ty_def_id);
-    let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy);
+    // No name because this is a synthetic associated type.
+    let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy);
 
     let local_def_id = trait_assoc_ty.def_id();
     let def_id = local_def_id.to_def_id();
@@ -304,7 +305,8 @@ fn associated_type_for_impl_trait_in_impl(
         hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id),
         hir::FnRetTy::Return(ty) => ty.span,
     };
-    let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, kw::Empty, DefKind::AssocTy);
+    // No name because this is a synthetic associated type.
+    let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy);
 
     let local_def_id = impl_assoc_ty.def_id();
     let def_id = local_def_id.to_def_id();
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index 2157ab3c402..20646cf9a82 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty
     is_item_raw(tcx, query, LangItem::Copy)
 }
 
+fn is_use_cloned_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
+) -> bool {
+    is_item_raw(tcx, query, LangItem::UseCloned)
+}
+
 fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
     is_item_raw(tcx, query, LangItem::Sized)
 }
@@ -33,5 +40,12 @@ fn is_item_raw<'tcx>(
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers };
+    *providers = Providers {
+        is_copy_raw,
+        is_use_cloned_raw,
+        is_sized_raw,
+        is_freeze_raw,
+        is_unpin_raw,
+        ..*providers
+    };
 }
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index ece796b3c71..b275cd382ab 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -230,7 +230,9 @@ fn recurse_build<'tcx>(
             error(GenericConstantTooComplexSub::LoopNotSupported(node.span))?
         }
         ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?,
-
+        ExprKind::ByUse { .. } => {
+            error(GenericConstantTooComplexSub::ByUseNotSupported(node.span))?
+        }
         ExprKind::Unary { .. } => unreachable!(),
         // we handle valid unary/binary ops above
         ExprKind::Binary { .. } => {
@@ -317,6 +319,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
             | thir::ExprKind::Box { .. }
             | thir::ExprKind::If { .. }
             | thir::ExprKind::Call { .. }
+            | thir::ExprKind::ByUse { .. }
             | thir::ExprKind::Deref { .. }
             | thir::ExprKind::Binary { .. }
             | thir::ExprKind::LogicalOp { .. }
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 8877bb45ceb..0298e7e0e95 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -55,6 +55,8 @@ pub(crate) enum GenericConstantTooComplexSub {
     BoxNotSupported(#[primary_span] Span),
     #[label(ty_utils_binary_not_supported)]
     BinaryNotSupported(#[primary_span] Span),
+    #[label(ty_utils_by_use_not_supported)]
+    ByUseNotSupported(#[primary_span] Span),
     #[label(ty_utils_logical_op_not_supported)]
     LogicalOpNotSupported(#[primary_span] Span),
     #[label(ty_utils_assign_not_supported)]
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index a53f0538c58..5a4bb2c95da 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -1,31 +1,25 @@
-use std::fmt::Debug;
-use std::iter;
-
 use hir::def_id::DefId;
 use rustc_abi::Integer::{I8, I32};
 use rustc_abi::Primitive::{self, Float, Int, Pointer};
 use rustc_abi::{
-    AbiAndPrefAlign, AddressSpace, Align, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape,
-    HasDataLayout, Layout, LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size,
-    StructKind, TagEncoding, VariantIdx, Variants, WrappingRange,
+    AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
+    LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
+    VariantIdx, Variants, WrappingRange,
 };
 use rustc_hashes::Hash64;
-use rustc_index::bit_set::DenseBitSet;
-use rustc_index::{IndexSlice, IndexVec};
+use rustc_index::IndexVec;
 use rustc_middle::bug;
-use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{
-    FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, MAX_SIMD_LANES, TyAndLayout,
+    FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
-    TypeVisitableExt,
+    self, AdtDef, CoroutineArgsExt, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt, TypeVisitableExt,
 };
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::{Symbol, sym};
-use tracing::{debug, instrument, trace};
+use tracing::{debug, instrument};
 use {rustc_abi as abi, rustc_hir as hir};
 
 use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType};
@@ -124,20 +118,23 @@ fn map_error<'tcx>(
                 .delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}"));
             LayoutError::ReferencesError(guar)
         }
+        LayoutCalculatorError::ZeroLengthSimdType => {
+            // Can't be caught in typeck if the array length is generic.
+            cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty })
+        }
+        LayoutCalculatorError::OversizedSimdType { max_lanes } => {
+            // Can't be caught in typeck if the array length is generic.
+            cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes })
+        }
+        LayoutCalculatorError::NonPrimitiveSimdType(field) => {
+            // This error isn't caught in typeck, e.g., if
+            // the element type of the vector is generic.
+            cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty })
+        }
     };
     error(cx, err)
 }
 
-fn univariant_uninterned<'tcx>(
-    cx: &LayoutCx<'tcx>,
-    ty: Ty<'tcx>,
-    fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
-    kind: StructKind,
-) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
-    let repr = ReprOptions::default();
-    cx.calc.univariant(fields, &repr, kind).map_err(|err| map_error(cx, ty, err))
-}
-
 fn extract_const_value<'tcx>(
     cx: &LayoutCx<'tcx>,
     ty: Ty<'tcx>,
@@ -188,6 +185,10 @@ fn layout_of_uncached<'tcx>(
 
     let tcx = cx.tcx();
     let dl = cx.data_layout();
+    let map_layout = |result: Result<_, _>| match result {
+        Ok(layout) => Ok(tcx.mk_layout(layout)),
+        Err(err) => Err(map_error(cx, ty, err)),
+    };
     let scalar_unit = |value: Primitive| {
         let size = value.size(dl);
         assert!(size.bits() <= 128);
@@ -195,8 +196,10 @@ fn layout_of_uncached<'tcx>(
     };
     let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
 
-    let univariant = |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, kind| {
-        Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, kind)?))
+    let univariant = |tys: &[Ty<'tcx>], kind| {
+        let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::<IndexVec<_, _>>()?;
+        let repr = ReprOptions::default();
+        map_layout(cx.calc.univariant(&fields, &repr, kind))
     };
     debug_assert!(!ty.has_non_region_infer());
 
@@ -258,7 +261,7 @@ fn layout_of_uncached<'tcx>(
         }
 
         // The never type.
-        ty::Never => tcx.mk_layout(cx.calc.layout_of_never_type()),
+        ty::Never => tcx.mk_layout(LayoutData::never_type(cx)),
 
         // Potentially-wide pointers.
         ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
@@ -329,7 +332,7 @@ fn layout_of_uncached<'tcx>(
             };
 
             // Effectively a (ptr, meta) tuple.
-            tcx.mk_layout(cx.calc.scalar_pair(data_ptr, metadata))
+            tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata))
         }
 
         ty::Dynamic(_, _, ty::DynStar) => {
@@ -337,7 +340,7 @@ fn layout_of_uncached<'tcx>(
             data.valid_range_mut().start = 0;
             let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
             vtable.valid_range_mut().start = 1;
-            tcx.mk_layout(cx.calc.scalar_pair(data, vtable))
+            tcx.mk_layout(LayoutData::scalar_pair(cx, data, vtable))
         }
 
         // Arrays and slices.
@@ -347,96 +350,87 @@ fn layout_of_uncached<'tcx>(
                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
 
             let element = cx.layout_of(element)?;
-            let size = element
-                .size
-                .checked_mul(count, dl)
-                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
-
-            let abi = BackendRepr::Memory { sized: true };
-
-            let largest_niche = if count != 0 { element.largest_niche } else { None };
-            let uninhabited = if count != 0 { element.uninhabited } else { false };
-
-            tcx.mk_layout(LayoutData {
-                variants: Variants::Single { index: FIRST_VARIANT },
-                fields: FieldsShape::Array { stride: element.size, count },
-                backend_repr: abi,
-                largest_niche,
-                uninhabited,
-                align: element.align,
-                size,
-                max_repr_align: None,
-                unadjusted_abi_align: element.align.abi,
-                randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
-            })
+            map_layout(cx.calc.array_like(&element, Some(count)))?
         }
         ty::Slice(element) => {
             let element = cx.layout_of(element)?;
-            tcx.mk_layout(LayoutData {
-                variants: Variants::Single { index: FIRST_VARIANT },
-                fields: FieldsShape::Array { stride: element.size, count: 0 },
-                backend_repr: BackendRepr::Memory { sized: false },
-                largest_niche: None,
-                uninhabited: false,
-                align: element.align,
-                size: Size::ZERO,
-                max_repr_align: None,
-                unadjusted_abi_align: element.align.abi,
-                // adding a randomly chosen value to distinguish slices
-                randomization_seed: element
-                    .randomization_seed
-                    .wrapping_add(Hash64::new(0x2dcba99c39784102)),
-            })
+            map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
+                // a randomly chosen value to distinguish slices
+                layout.randomization_seed = Hash64::new(0x2dcba99c39784102);
+                layout
+            }))?
+        }
+        ty::Str => {
+            let element = scalar(Int(I8, false));
+            map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
+                // another random value
+                layout.randomization_seed = Hash64::new(0xc1325f37d127be22);
+                layout
+            }))?
         }
-        ty::Str => tcx.mk_layout(LayoutData {
-            variants: Variants::Single { index: FIRST_VARIANT },
-            fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
-            backend_repr: BackendRepr::Memory { sized: false },
-            largest_niche: None,
-            uninhabited: false,
-            align: dl.i8_align,
-            size: Size::ZERO,
-            max_repr_align: None,
-            unadjusted_abi_align: dl.i8_align.abi,
-            // another random value
-            randomization_seed: Hash64::new(0xc1325f37d127be22),
-        }),
 
         // Odd unit types.
-        ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?,
-        ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
-            let mut unit =
-                univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?;
-            match unit.backend_repr {
-                BackendRepr::Memory { ref mut sized } => *sized = false,
-                _ => bug!(),
-            }
-            tcx.mk_layout(unit)
+        ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
+            let sized = matches!(ty.kind(), ty::FnDef(..));
+            tcx.mk_layout(LayoutData::unit(cx, sized))
         }
 
-        ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
+        ty::Coroutine(def_id, args) => {
+            use rustc_middle::ty::layout::PrimitiveExt as _;
+
+            let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else {
+                return Err(error(cx, LayoutError::Unknown(ty)));
+            };
+
+            let local_layouts = info
+                .field_tys
+                .iter()
+                .map(|local| {
+                    let field_ty = EarlyBinder::bind(local.ty);
+                    let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args));
+                    cx.spanned_layout_of(uninit_ty, local.source_info.span)
+                })
+                .try_collect::<IndexVec<_, _>>()?;
 
-        ty::Closure(_, args) => {
-            let tys = args.as_closure().upvar_tys();
-            univariant(
-                &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
-                StructKind::AlwaysSized,
-            )?
+            let prefix_layouts = args
+                .as_coroutine()
+                .prefix_tys()
+                .iter()
+                .map(|ty| cx.layout_of(ty))
+                .try_collect::<IndexVec<_, _>>()?;
+
+            let layout = cx
+                .calc
+                .coroutine(
+                    &local_layouts,
+                    prefix_layouts,
+                    &info.variant_fields,
+                    &info.storage_conflicts,
+                    |tag| TyAndLayout {
+                        ty: tag.primitive().to_ty(tcx),
+                        layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
+                    },
+                )
+                .map(|mut layout| {
+                    // this is similar to how ReprOptions populates its field_shuffle_seed
+                    layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash();
+                    debug!("coroutine layout ({:?}): {:#?}", ty, layout);
+                    layout
+                });
+            map_layout(layout)?
         }
 
+        ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?,
+
         ty::CoroutineClosure(_, args) => {
-            let tys = args.as_coroutine_closure().upvar_tys();
-            univariant(
-                &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
-                StructKind::AlwaysSized,
-            )?
+            univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)?
         }
 
         ty::Tuple(tys) => {
             let kind =
                 if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
 
-            univariant(&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?, kind)?
+            univariant(tys, kind)?
         }
 
         // SIMD vector types.
@@ -461,65 +455,9 @@ fn layout_of_uncached<'tcx>(
                 .try_to_target_usize(tcx)
                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
 
-            // SIMD vectors of zero length are not supported.
-            // Additionally, lengths are capped at 2^16 as a fixed maximum backends must
-            // support.
-            //
-            // Can't be caught in typeck if the array length is generic.
-            if e_len == 0 {
-                tcx.dcx().emit_fatal(ZeroLengthSimdType { ty });
-            } else if e_len > MAX_SIMD_LANES {
-                tcx.dcx().emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES });
-            }
-
-            // Compute the ABI of the element type:
             let e_ly = cx.layout_of(e_ty)?;
-            let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else {
-                // This error isn't caught in typeck, e.g., if
-                // the element type of the vector is generic.
-                tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty });
-            };
 
-            // Compute the size and alignment of the vector:
-            let size = e_ly
-                .size
-                .checked_mul(e_len, dl)
-                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
-
-            let (abi, align) = if def.repr().packed() && !e_len.is_power_of_two() {
-                // Non-power-of-two vectors have padding up to the next power-of-two.
-                // If we're a packed repr, remove the padding while keeping the alignment as close
-                // to a vector as possible.
-                (
-                    BackendRepr::Memory { sized: true },
-                    AbiAndPrefAlign {
-                        abi: Align::max_aligned_factor(size),
-                        pref: dl.llvmlike_vector_align(size).pref,
-                    },
-                )
-            } else {
-                (
-                    BackendRepr::SimdVector { element: e_abi, count: e_len },
-                    dl.llvmlike_vector_align(size),
-                )
-            };
-            let size = size.align_to(align.abi);
-
-            tcx.mk_layout(LayoutData {
-                variants: Variants::Single { index: FIRST_VARIANT },
-                fields: FieldsShape::Arbitrary {
-                    offsets: [Size::ZERO].into(),
-                    memory_index: [0].into(),
-                },
-                backend_repr: abi,
-                largest_niche: e_ly.largest_niche,
-                uninhabited: false,
-                size,
-                align,
-                max_repr_align: None,
-                unadjusted_abi_align: align.abi,
-                randomization_seed: e_ly.randomization_seed.wrapping_add(Hash64::new(e_len)),
-            })
+            map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
         }
 
         // ADTs.
@@ -545,11 +483,7 @@ fn layout_of_uncached<'tcx>(
                     return Err(error(cx, LayoutError::ReferencesError(guar)));
                 }
 
-                return Ok(tcx.mk_layout(
-                    cx.calc
-                        .layout_of_union(&def.repr(), &variants)
-                        .map_err(|err| map_error(cx, ty, err))?,
-                ));
+                return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
             }
 
             let get_discriminant_type =
@@ -677,335 +611,6 @@ fn layout_of_uncached<'tcx>(
     })
 }
 
-/// Overlap eligibility and variant assignment for each CoroutineSavedLocal.
-#[derive(Clone, Debug, PartialEq)]
-enum SavedLocalEligibility {
-    Unassigned,
-    Assigned(VariantIdx),
-    Ineligible(Option<FieldIdx>),
-}
-
-// When laying out coroutines, we divide our saved local fields into two
-// categories: overlap-eligible and overlap-ineligible.
-//
-// Those fields which are ineligible for overlap go in a "prefix" at the
-// beginning of the layout, and always have space reserved for them.
-//
-// Overlap-eligible fields are only assigned to one variant, so we lay
-// those fields out for each variant and put them right after the
-// prefix.
-//
-// Finally, in the layout details, we point to the fields from the
-// variants they are assigned to. It is possible for some fields to be
-// included in multiple variants. No field ever "moves around" in the
-// layout; its offset is always the same.
-//
-// Also included in the layout are the upvars and the discriminant.
-// These are included as fields on the "outer" layout; they are not part
-// of any variant.
-
-/// Compute the eligibility and assignment of each local.
-fn coroutine_saved_local_eligibility(
-    info: &CoroutineLayout<'_>,
-) -> (DenseBitSet<CoroutineSavedLocal>, IndexVec<CoroutineSavedLocal, SavedLocalEligibility>) {
-    use SavedLocalEligibility::*;
-
-    let mut assignments: IndexVec<CoroutineSavedLocal, SavedLocalEligibility> =
-        IndexVec::from_elem(Unassigned, &info.field_tys);
-
-    // The saved locals not eligible for overlap. These will get
-    // "promoted" to the prefix of our coroutine.
-    let mut ineligible_locals = DenseBitSet::new_empty(info.field_tys.len());
-
-    // Figure out which of our saved locals are fields in only
-    // one variant. The rest are deemed ineligible for overlap.
-    for (variant_index, fields) in info.variant_fields.iter_enumerated() {
-        for local in fields {
-            match assignments[*local] {
-                Unassigned => {
-                    assignments[*local] = Assigned(variant_index);
-                }
-                Assigned(idx) => {
-                    // We've already seen this local at another suspension
-                    // point, so it is no longer a candidate.
-                    trace!(
-                        "removing local {:?} in >1 variant ({:?}, {:?})",
-                        local, variant_index, idx
-                    );
-                    ineligible_locals.insert(*local);
-                    assignments[*local] = Ineligible(None);
-                }
-                Ineligible(_) => {}
-            }
-        }
-    }
-
-    // Next, check every pair of eligible locals to see if they
-    // conflict.
-    for local_a in info.storage_conflicts.rows() {
-        let conflicts_a = info.storage_conflicts.count(local_a);
-        if ineligible_locals.contains(local_a) {
-            continue;
-        }
-
-        for local_b in info.storage_conflicts.iter(local_a) {
-            // local_a and local_b are storage live at the same time, therefore they
-            // cannot overlap in the coroutine layout. The only way to guarantee
-            // this is if they are in the same variant, or one is ineligible
-            // (which means it is stored in every variant).
-            if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] {
-                continue;
-            }
-
-            // If they conflict, we will choose one to make ineligible.
-            // This is not always optimal; it's just a greedy heuristic that
-            // seems to produce good results most of the time.
-            let conflicts_b = info.storage_conflicts.count(local_b);
-            let (remove, other) =
-                if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) };
-            ineligible_locals.insert(remove);
-            assignments[remove] = Ineligible(None);
-            trace!("removing local {:?} due to conflict with {:?}", remove, other);
-        }
-    }
-
-    // Count the number of variants in use. If only one of them, then it is
-    // impossible to overlap any locals in our layout. In this case it's
-    // always better to make the remaining locals ineligible, so we can
-    // lay them out with the other locals in the prefix and eliminate
-    // unnecessary padding bytes.
-    {
-        let mut used_variants = DenseBitSet::new_empty(info.variant_fields.len());
-        for assignment in &assignments {
-            if let Assigned(idx) = assignment {
-                used_variants.insert(*idx);
-            }
-        }
-        if used_variants.count() < 2 {
-            for assignment in assignments.iter_mut() {
-                *assignment = Ineligible(None);
-            }
-            ineligible_locals.insert_all();
-        }
-    }
-
-    // Write down the order of our locals that will be promoted to the prefix.
-    {
-        for (idx, local) in ineligible_locals.iter().enumerate() {
-            assignments[local] = Ineligible(Some(FieldIdx::from_usize(idx)));
-        }
-    }
-    debug!("coroutine saved local assignments: {:?}", assignments);
-
-    (ineligible_locals, assignments)
-}
-
-/// Compute the full coroutine layout.
-fn coroutine_layout<'tcx>(
-    cx: &LayoutCx<'tcx>,
-    ty: Ty<'tcx>,
-    def_id: hir::def_id::DefId,
-    args: GenericArgsRef<'tcx>,
-) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
-    use SavedLocalEligibility::*;
-    let tcx = cx.tcx();
-    let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args);
-
-    let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else {
-        return Err(error(cx, LayoutError::Unknown(ty)));
-    };
-    let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info);
-
-    // Build a prefix layout, including "promoting" all ineligible
-    // locals as part of the prefix. We compute the layout of all of
-    // these fields at once to get optimal packing.
-    let tag_index = args.as_coroutine().prefix_tys().len();
-
-    // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
-    let max_discr = (info.variant_fields.len() - 1) as u128;
-    let discr_int = abi::Integer::fit_unsigned(max_discr);
-    let tag = Scalar::Initialized {
-        value: Primitive::Int(discr_int, /* signed = */ false),
-        valid_range: WrappingRange { start: 0, end: max_discr },
-    };
-    let tag_layout = TyAndLayout {
-        ty: discr_int.to_ty(tcx, /* signed = */ false),
-        layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
-    };
-
-    let promoted_layouts = ineligible_locals.iter().map(|local| {
-        let field_ty = instantiate_field(info.field_tys[local].ty);
-        let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty);
-        cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)
-    });
-    let prefix_layouts = args
-        .as_coroutine()
-        .prefix_tys()
-        .iter()
-        .map(|ty| cx.layout_of(ty))
-        .chain(iter::once(Ok(tag_layout)))
-        .chain(promoted_layouts)
-        .try_collect::<IndexVec<_, _>>()?;
-    let prefix = univariant_uninterned(cx, ty, &prefix_layouts, StructKind::AlwaysSized)?;
-
-    let (prefix_size, prefix_align) = (prefix.size, prefix.align);
-
-    // Split the prefix layout into the "outer" fields (upvars and
-    // discriminant) and the "promoted" fields. Promoted fields will
-    // get included in each variant that requested them in
-    // CoroutineLayout.
-    debug!("prefix = {:#?}", prefix);
-    let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
-        FieldsShape::Arbitrary { mut offsets, memory_index } => {
-            let mut inverse_memory_index = memory_index.invert_bijective_mapping();
-
-            // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
-            // "outer" and "promoted" fields respectively.
-            let b_start = FieldIdx::from_usize(tag_index + 1);
-            let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.as_usize()));
-            let offsets_a = offsets;
-
-            // Disentangle the "a" and "b" components of `inverse_memory_index`
-            // by preserving the order but keeping only one disjoint "half" each.
-            // FIXME(eddyb) build a better abstraction for permutations, if possible.
-            let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index
-                .iter()
-                .filter_map(|&i| i.as_u32().checked_sub(b_start.as_u32()).map(FieldIdx::from_u32))
-                .collect();
-            inverse_memory_index.raw.retain(|&i| i < b_start);
-            let inverse_memory_index_a = inverse_memory_index;
-
-            // Since `inverse_memory_index_{a,b}` each only refer to their
-            // respective fields, they can be safely inverted
-            let memory_index_a = inverse_memory_index_a.invert_bijective_mapping();
-            let memory_index_b = inverse_memory_index_b.invert_bijective_mapping();
-
-            let outer_fields =
-                FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
-            (outer_fields, offsets_b, memory_index_b)
-        }
-        _ => bug!(),
-    };
-
-    let mut size = prefix.size;
-    let mut align = prefix.align;
-    let variants = info
-        .variant_fields
-        .iter_enumerated()
-        .map(|(index, variant_fields)| {
-            // Only include overlap-eligible fields when we compute our variant layout.
-            let variant_only_tys = variant_fields
-                .iter()
-                .filter(|local| match assignments[**local] {
-                    Unassigned => bug!(),
-                    Assigned(v) if v == index => true,
-                    Assigned(_) => bug!("assignment does not match variant"),
-                    Ineligible(_) => false,
-                })
-                .map(|local| {
-                    let field_ty = instantiate_field(info.field_tys[*local].ty);
-                    Ty::new_maybe_uninit(tcx, field_ty)
-                });
-
-            let mut variant = univariant_uninterned(
-                cx,
-                ty,
-                &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
-                StructKind::Prefixed(prefix_size, prefix_align.abi),
-            )?;
-            variant.variants = Variants::Single { index };
-
-            let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
-                bug!();
-            };
-
-            // Now, stitch the promoted and variant-only fields back together in
-            // the order they are mentioned by our CoroutineLayout.
-            // Because we only use some subset (that can differ between variants)
-            // of the promoted fields, we can't just pick those elements of the
-            // `promoted_memory_index` (as we'd end up with gaps).
-            // So instead, we build an "inverse memory_index", as if all of the
-            // promoted fields were being used, but leave the elements not in the
-            // subset as `INVALID_FIELD_IDX`, which we can filter out later to
-            // obtain a valid (bijective) mapping.
-            const INVALID_FIELD_IDX: FieldIdx = FieldIdx::MAX;
-            debug_assert!(variant_fields.next_index() <= INVALID_FIELD_IDX);
-
-            let mut combined_inverse_memory_index = IndexVec::from_elem_n(
-                INVALID_FIELD_IDX,
-                promoted_memory_index.len() + memory_index.len(),
-            );
-            let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
-            let combined_offsets = variant_fields
-                .iter_enumerated()
-                .map(|(i, local)| {
-                    let (offset, memory_index) = match assignments[*local] {
-                        Unassigned => bug!(),
-                        Assigned(_) => {
-                            let (offset, memory_index) = offsets_and_memory_index.next().unwrap();
-                            (offset, promoted_memory_index.len() as u32 + memory_index)
-                        }
-                        Ineligible(field_idx) => {
-                            let field_idx = field_idx.unwrap();
-                            (promoted_offsets[field_idx], promoted_memory_index[field_idx])
-                        }
-                    };
-                    combined_inverse_memory_index[memory_index] = i;
-                    offset
-                })
-                .collect();
-
-            // Remove the unused slots and invert the mapping to obtain the
-            // combined `memory_index` (also see previous comment).
-            combined_inverse_memory_index.raw.retain(|&i| i != INVALID_FIELD_IDX);
-            let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping();
-
-            variant.fields = FieldsShape::Arbitrary {
-                offsets: combined_offsets,
-                memory_index: combined_memory_index,
-            };
-
-            size = size.max(variant.size);
-            align = align.max(variant.align);
-            Ok(variant)
-        })
-        .try_collect::<IndexVec<VariantIdx, _>>()?;
-
-    size = size.align_to(align.abi);
-
-    let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited());
-    let abi = BackendRepr::Memory { sized: true };
-
-    // this is similar to how ReprOptions populates its field_shuffle_seed
-    let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash();
-
-    let layout = tcx.mk_layout(LayoutData {
-        variants: Variants::Multiple {
-            tag,
-            tag_encoding: TagEncoding::Direct,
-            tag_field: tag_index,
-            variants,
-        },
-        fields: outer_fields,
-        backend_repr: abi,
-        // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to
-        // self-referentiality), getting the discriminant can cause aliasing violations.
-        // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that
-        // would do the same for us here.
-        // See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>.
-        // FIXME: Remove when <https://github.com/rust-lang/rust/issues/125735> is implemented and aliased coroutine fields are wrapped in `UnsafePinned`.
-        largest_niche: None,
-        uninhabited,
-        size,
-        align,
-        max_repr_align: None,
-        unadjusted_abi_align: align.abi,
-        randomization_seed: def_hash,
-    });
-    debug!("coroutine layout ({:?}): {:#?}", ty, layout);
-    Ok(layout)
-}
-
 fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) {
     // Ignore layouts that are done with non-empty environments or
     // non-monomorphic layouts, as the user only wants to see the stuff
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 8610c30ab70..bb61f4bee66 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -6,13 +6,11 @@ use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::fold::fold_regions;
-use rustc_middle::ty::{
-    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_trait_selection::traits;
-use tracing::{debug, instrument};
+use tracing::instrument;
 
 #[instrument(level = "debug", skip(tcx), ret)]
 fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
@@ -260,57 +258,6 @@ fn param_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty:
     typing_env.with_post_analysis_normalized(tcx).param_env
 }
 
-/// If the given trait impl enables exploiting the former order dependence of trait objects,
-/// returns its self type; otherwise, returns `None`.
-///
-/// See [`ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects`] for more details.
-#[instrument(level = "debug", skip(tcx))]
-fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(
-    tcx: TyCtxt<'_>,
-    def_id: DefId,
-) -> Option<EarlyBinder<'_, Ty<'_>>> {
-    let impl_ =
-        tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}"));
-
-    let trait_ref = impl_.trait_ref.skip_binder();
-    debug!(?trait_ref);
-
-    let is_marker_like = impl_.polarity == ty::ImplPolarity::Positive
-        && tcx.associated_item_def_ids(trait_ref.def_id).is_empty();
-
-    // Check whether these impls would be ok for a marker trait.
-    if !is_marker_like {
-        debug!("not marker-like!");
-        return None;
-    }
-
-    // impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
-    if trait_ref.args.len() != 1 {
-        debug!("impl has args!");
-        return None;
-    }
-
-    let predicates = tcx.predicates_of(def_id);
-    if predicates.parent.is_some() || !predicates.predicates.is_empty() {
-        debug!(?predicates, "impl has predicates!");
-        return None;
-    }
-
-    let self_ty = trait_ref.self_ty();
-    let self_ty_matches = match self_ty.kind() {
-        ty::Dynamic(data, re, _) if re.is_static() => data.principal().is_none(),
-        _ => false,
-    };
-
-    if self_ty_matches {
-        debug!("MATCHES!");
-        Some(EarlyBinder::bind(self_ty))
-    } else {
-        debug!("non-matching self type");
-        None
-    }
-}
-
 /// Check if a function is async.
 fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness {
     let node = tcx.hir_node_by_def_id(def_id);
@@ -370,7 +317,6 @@ pub(crate) fn provide(providers: &mut Providers) {
         adt_sized_constraint,
         param_env,
         param_env_normalized_for_post_analysis,
-        self_ty_of_trait_impl_enabling_order_dep_trait_object_hack,
         defaultness,
         unsizing_params_for_adt,
         ..*providers
diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs
index 7e0c4a479b8..023807b76ae 100644
--- a/compiler/stable_mir/src/mir/alloc.rs
+++ b/compiler/stable_mir/src/mir/alloc.rs
@@ -58,7 +58,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>()];
+    let mut buf = [0u8; size_of::<u128>()];
     match MachineInfo::target_endianness() {
         Endian::Little => {
             bytes.read_exact(&mut buf[..bytes.len()])?;
@@ -73,7 +73,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>()];
+    let mut buf = [0u8; size_of::<i128>()];
     match MachineInfo::target_endianness() {
         Endian::Little => {
             bytes.read_exact(&mut buf[..bytes.len()])?;
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 31656414121..8f174f28472 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -30,8 +30,6 @@ version = "0.0.0"
 dependencies = [
  "compiler_builtins",
  "core",
- "rand",
- "rand_xorshift",
 ]
 
 [[package]]
@@ -41,6 +39,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
+name = "alloctests"
+version = "0.0.0"
+dependencies = [
+ "rand",
+ "rand_xorshift",
+]
+
+[[package]]
 name = "cc"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -140,9 +146,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
+checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
diff --git a/library/Cargo.toml b/library/Cargo.toml
index 1205f7c9ed6..4d5955593ff 100644
--- a/library/Cargo.toml
+++ b/library/Cargo.toml
@@ -4,6 +4,7 @@ members = [
   "std",
   "sysroot",
   "coretests",
+  "alloctests",
 ]
 
 exclude = [
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 4cb83501256..dbdf292433b 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -10,32 +10,14 @@ autotests = false
 autobenches = false
 edition = "2021"
 
+[lib]
+test = false
+bench = false
+
 [dependencies]
 core = { path = "../core", public = true }
 compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
 
-[dev-dependencies]
-rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
-rand_xorshift = "0.4.0"
-
-[[test]]
-name = "alloctests"
-path = "tests/lib.rs"
-
-[[test]]
-name = "vec_deque_alloc_error"
-path = "tests/vec_deque_alloc_error.rs"
-
-[[bench]]
-name = "allocbenches"
-path = "benches/lib.rs"
-test = true
-
-[[bench]]
-name = "vec_deque_append_bench"
-path = "benches/vec_deque_append.rs"
-harness = false
-
 [features]
 compiler-builtins-mem = ['compiler_builtins/mem']
 compiler-builtins-c = ["compiler_builtins/c"]
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 3bfdc68dcda..2f752f6eb39 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -5,9 +5,7 @@
 #[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
 pub use core::alloc::*;
-#[cfg(not(test))]
 use core::hint;
-#[cfg(not(test))]
 use core::ptr::{self, NonNull};
 
 unsafe extern "Rust" {
@@ -44,14 +42,10 @@ unsafe extern "Rust" {
 /// accessed through the [free functions in `alloc`](self#functions).
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, Default, Debug)]
-#[cfg(not(test))]
 // the compiler needs to know when a Box uses the global allocator vs a custom one
 #[lang = "global_alloc_ty"]
 pub struct Global;
 
-#[cfg(test)]
-pub use std::alloc::Global;
-
 /// Allocates memory with the global allocator.
 ///
 /// This function forwards calls to the [`GlobalAlloc::alloc`] method
@@ -180,7 +174,6 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
     }
 }
 
-#[cfg(not(test))]
 impl Global {
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -246,7 +239,6 @@ impl Global {
 }
 
 #[unstable(feature = "allocator_api", issue = "32838")]
-#[cfg(not(test))]
 unsafe impl Allocator for Global {
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -346,7 +338,7 @@ unsafe impl Allocator for Global {
 }
 
 /// The allocator for `Box`.
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[lang = "exchange_malloc"]
 #[inline]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -395,7 +387,7 @@ unsafe extern "Rust" {
 /// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[cold]
 #[optimize(size)]
 pub const fn handle_alloc_error(layout: Layout) -> ! {
@@ -419,11 +411,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
     ct_error(layout)
 }
 
-// For alloc test `std::alloc::handle_alloc_error` can be used directly.
-#[cfg(all(not(no_global_oom_handling), test))]
-pub use std::alloc::handle_alloc_error;
-
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index 17dad3277b9..07f51b7614f 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -32,7 +32,7 @@ where
 /// implementing the `Clone` trait. But `Clone` works only for going from `&T`
 /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
 /// from any borrow of a given type.
-#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")]
+#[rustc_diagnostic_item = "ToOwned"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ToOwned {
     /// The resulting type after obtaining ownership.
@@ -54,7 +54,7 @@ pub trait ToOwned {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "cloning is often expensive and is not expected to have side effects"]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_method")]
+    #[rustc_diagnostic_item = "to_owned_method"]
     fn to_owned(&self) -> Self::Owned;
 
     /// Uses borrowed data to replace owned data, usually by cloning.
@@ -175,7 +175,7 @@ where
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")]
+#[rustc_diagnostic_item = "Cow"]
 pub enum Cow<'a, B: ?Sized + 'a>
 where
     B: ToOwned,
diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs
index 255cefb1e78..80626580202 100644
--- a/library/alloc/src/boxed/convert.rs
+++ b/library/alloc/src/boxed/convert.rs
@@ -529,7 +529,6 @@ impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     /// ```
     /// use std::error::Error;
     /// use std::fmt;
-    /// use std::mem;
     ///
     /// #[derive(Debug)]
     /// struct AnError;
@@ -543,9 +542,9 @@ impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     /// impl Error for AnError {}
     ///
     /// let an_error = AnError;
-    /// assert!(0 == mem::size_of_val(&an_error));
+    /// assert!(0 == size_of_val(&an_error));
     /// let a_boxed_error = Box::<dyn Error>::from(an_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// assert!(size_of::<Box<dyn Error>>() == size_of_val(&a_boxed_error))
     /// ```
     fn from(err: E) -> Box<dyn Error + 'a> {
         Box::new(err)
@@ -563,7 +562,6 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     /// ```
     /// use std::error::Error;
     /// use std::fmt;
-    /// use std::mem;
     ///
     /// #[derive(Debug)]
     /// struct AnError;
@@ -581,10 +579,10 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     /// unsafe impl Sync for AnError {}
     ///
     /// let an_error = AnError;
-    /// assert!(0 == mem::size_of_val(&an_error));
+    /// assert!(0 == size_of_val(&an_error));
     /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
     /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    ///     size_of::<Box<dyn Error + Send + Sync>>() == size_of_val(&a_boxed_error))
     /// ```
     fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
         Box::new(err)
@@ -600,12 +598,11 @@ impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
     ///
     /// ```
     /// use std::error::Error;
-    /// use std::mem;
     ///
     /// let a_string_error = "a string error".to_string();
     /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
     /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    ///     size_of::<Box<dyn Error + Send + Sync>>() == size_of_val(&a_boxed_error))
     /// ```
     #[inline]
     fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
@@ -644,11 +641,10 @@ impl<'a> From<String> for Box<dyn Error + 'a> {
     ///
     /// ```
     /// use std::error::Error;
-    /// use std::mem;
     ///
     /// let a_string_error = "a string error".to_string();
     /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// assert!(size_of::<Box<dyn Error>>() == size_of_val(&a_boxed_error))
     /// ```
     fn from(str_err: String) -> Box<dyn Error + 'a> {
         let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
@@ -668,12 +664,11 @@ impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
     ///
     /// ```
     /// use std::error::Error;
-    /// use std::mem;
     ///
     /// let a_str_error = "a str error";
     /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
     /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    ///     size_of::<Box<dyn Error + Send + Sync>>() == size_of_val(&a_boxed_error))
     /// ```
     #[inline]
     fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
@@ -692,11 +687,10 @@ impl<'a> From<&str> for Box<dyn Error + 'a> {
     ///
     /// ```
     /// use std::error::Error;
-    /// use std::mem;
     ///
     /// let a_str_error = "a str error";
     /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// assert!(size_of::<Box<dyn Error>>() == size_of_val(&a_boxed_error))
     /// ```
     fn from(err: &str) -> Box<dyn Error + 'a> {
         From::from(String::from(err))
@@ -712,13 +706,12 @@ impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
     ///
     /// ```
     /// use std::error::Error;
-    /// use std::mem;
     /// use std::borrow::Cow;
     ///
     /// let a_cow_str_error = Cow::from("a str error");
     /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
     /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    ///     size_of::<Box<dyn Error + Send + Sync>>() == size_of_val(&a_boxed_error))
     /// ```
     fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
         From::from(String::from(err))
@@ -734,12 +727,11 @@ impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
     ///
     /// ```
     /// use std::error::Error;
-    /// use std::mem;
     /// use std::borrow::Cow;
     ///
     /// let a_cow_str_error = Cow::from("a str error");
     /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// assert!(size_of::<Box<dyn Error>>() == size_of_val(&a_boxed_error))
     /// ```
     fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
         From::from(String::from(err))
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 78e5aec09b1..21425b9846e 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -9,9 +9,8 @@ use core::intrinsics::const_allocate;
 use core::marker::PhantomData;
 #[cfg(not(no_global_oom_handling))]
 use core::marker::Unsize;
-use core::mem;
 #[cfg(not(no_global_oom_handling))]
-use core::mem::SizedTypeProperties;
+use core::mem::{self, SizedTypeProperties};
 use core::ops::{Deref, DerefMut};
 use core::ptr::{self, NonNull, Pointee};
 
@@ -30,7 +29,6 @@ use crate::alloc::{self, Layout, LayoutError};
 /// let five = ThinBox::new(5);
 /// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
 ///
-/// use std::mem::{size_of, size_of_val};
 /// let size_of_ptr = size_of::<*const ()>();
 /// assert_eq!(size_of_ptr, size_of_val(&five));
 /// assert_eq!(size_of_ptr, size_of_val(&thin_slice));
@@ -114,7 +112,7 @@ impl<Dyn: ?Sized> ThinBox<Dyn> {
     where
         T: Unsize<Dyn>,
     {
-        if mem::size_of::<T>() == 0 {
+        if size_of::<T>() == 0 {
             let ptr = WithOpaqueHeader::new_unsize_zst::<Dyn, T>(value);
             ThinBox { ptr, _marker: PhantomData }
         } else {
@@ -283,9 +281,7 @@ impl<H> WithHeader<H> {
             let ptr = if layout.size() == 0 {
                 // Some paranoia checking, mostly so that the ThinBox tests are
                 // more able to catch issues.
-                debug_assert!(
-                    value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
-                );
+                debug_assert!(value_offset == 0 && size_of::<T>() == 0 && size_of::<H>() == 0);
                 layout.dangling()
             } else {
                 let ptr = alloc::alloc(layout);
@@ -315,7 +311,7 @@ impl<H> WithHeader<H> {
         Dyn: Pointee<Metadata = H> + ?Sized,
         T: Unsize<Dyn>,
     {
-        assert!(mem::size_of::<T>() == 0);
+        assert!(size_of::<T>() == 0);
 
         const fn max(a: usize, b: usize) -> usize {
             if a > b { a } else { b }
@@ -329,18 +325,16 @@ impl<H> WithHeader<H> {
             // FIXME: just call `WithHeader::alloc_layout` with size reset to 0.
             // Currently that's blocked on `Layout::extend` not being `const fn`.
 
-            let alloc_align =
-                max(mem::align_of::<T>(), mem::align_of::<<Dyn as Pointee>::Metadata>());
+            let alloc_align = max(align_of::<T>(), align_of::<<Dyn as Pointee>::Metadata>());
 
-            let alloc_size =
-                max(mem::align_of::<T>(), mem::size_of::<<Dyn as Pointee>::Metadata>());
+            let alloc_size = max(align_of::<T>(), size_of::<<Dyn as Pointee>::Metadata>());
 
             unsafe {
                 // SAFETY: align is power of two because it is the maximum of two alignments.
                 let alloc: *mut u8 = const_allocate(alloc_size, alloc_align);
 
                 let metadata_offset =
-                    alloc_size.checked_sub(mem::size_of::<<Dyn as Pointee>::Metadata>()).unwrap();
+                    alloc_size.checked_sub(size_of::<<Dyn as Pointee>::Metadata>()).unwrap();
                 // SAFETY: adding offset within the allocation.
                 let metadata_ptr: *mut <Dyn as Pointee>::Metadata =
                     alloc.add(metadata_offset).cast();
@@ -421,7 +415,7 @@ impl<H> WithHeader<H> {
     }
 
     const fn header_size() -> usize {
-        mem::size_of::<H>()
+        size_of::<H>()
     }
 
     fn alloc_layout(value_layout: Layout) -> Result<(Layout, usize), LayoutError> {
diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs
index 61e61019b50..338c7ac7f88 100644
--- a/library/alloc/src/bstr.rs
+++ b/library/alloc/src/bstr.rs
@@ -12,13 +12,10 @@ use core::ops::{
     Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
     RangeTo, RangeToInclusive,
 };
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 use core::str::FromStr;
 use core::{fmt, hash};
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 use crate::borrow::{Cow, ToOwned};
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 use crate::boxed::Box;
 #[cfg(not(no_rc))]
 use crate::rc::Rc;
@@ -181,7 +178,6 @@ impl Default for ByteString {
 
 // Omitted due to inference failures
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<'a, const N: usize> From<&'a [u8; N]> for ByteString {
 //     #[inline]
@@ -190,7 +186,6 @@ impl Default for ByteString {
 //     }
 // }
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<const N: usize> From<[u8; N]> for ByteString {
 //     #[inline]
@@ -199,7 +194,6 @@ impl Default for ByteString {
 //     }
 // }
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<'a> From<&'a [u8]> for ByteString {
 //     #[inline]
@@ -226,7 +220,6 @@ impl From<ByteString> for Vec<u8> {
 
 // Omitted due to inference failures
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<'a> From<&'a str> for ByteString {
 //     #[inline]
@@ -243,7 +236,6 @@ impl From<ByteString> for Vec<u8> {
 //     }
 // }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<&'a ByteStr> for ByteString {
     #[inline]
@@ -252,7 +244,6 @@ impl<'a> From<&'a ByteStr> for ByteString {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<ByteString> for Cow<'a, ByteStr> {
     #[inline]
@@ -261,7 +252,6 @@ impl<'a> From<ByteString> for Cow<'a, ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> {
     #[inline]
@@ -330,7 +320,6 @@ impl FromIterator<ByteString> for ByteString {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl FromStr for ByteString {
     type Err = core::convert::Infallible;
@@ -488,7 +477,6 @@ impl PartialEq for ByteString {
 
 macro_rules! impl_partial_eq_ord_cow {
     ($lhs:ty, $rhs:ty) => {
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialEq<$rhs> for $lhs {
@@ -499,7 +487,6 @@ macro_rules! impl_partial_eq_ord_cow {
             }
         }
 
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialEq<$lhs> for $rhs {
@@ -510,7 +497,6 @@ macro_rules! impl_partial_eq_ord_cow {
             }
         }
 
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialOrd<$rhs> for $lhs {
@@ -521,7 +507,6 @@ macro_rules! impl_partial_eq_ord_cow {
             }
         }
 
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialOrd<$lhs> for $rhs {
@@ -572,7 +557,6 @@ impl PartialOrd for ByteString {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl ToOwned for ByteStr {
     type Owned = ByteString;
@@ -605,7 +589,6 @@ impl<'a> TryFrom<&'a ByteString> for &'a str {
 
 // Additional impls for `ByteStr` that require types from `alloc`:
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl Clone for Box<ByteStr> {
     #[inline]
@@ -614,7 +597,6 @@ impl Clone for Box<ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
     #[inline]
@@ -623,7 +605,6 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl From<Box<[u8]>> for Box<ByteStr> {
     #[inline]
@@ -633,7 +614,6 @@ impl From<Box<[u8]>> for Box<ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl From<Box<ByteStr>> for Box<[u8]> {
     #[inline]
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 965fd63a529..b764b8fa5d9 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -153,7 +153,9 @@ use core::{fmt, ptr};
 use crate::alloc::Global;
 use crate::collections::TryReserveError;
 use crate::slice;
-use crate::vec::{self, AsVecIntoIter, Vec};
+#[cfg(not(test))]
+use crate::vec::AsVecIntoIter;
+use crate::vec::{self, Vec};
 
 /// A priority queue implemented with a binary heap.
 ///
@@ -1600,6 +1602,7 @@ unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {
     const MERGE_BY: Option<NonZero<usize>> = NonZero::new(1);
 }
 
+#[cfg(not(test))]
 unsafe impl<I> AsVecIntoIter for IntoIter<I> {
     type Item = I;
 
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index ecd009f11c7..7d1a2ea4809 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -92,8 +92,8 @@ fn test_partial_eq() {
 #[cfg(target_arch = "x86_64")]
 #[cfg_attr(any(miri, randomized_layouts), ignore)] // We'd like to run Miri with layout randomization
 fn test_sizes() {
-    assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
-    assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8);
-    assert_eq!(core::mem::size_of::<InternalNode<(), ()>>(), 16 + (CAPACITY + 1) * 8);
-    assert_eq!(core::mem::size_of::<InternalNode<i64, i64>>(), 16 + (CAPACITY * 3 + 1) * 8);
+    assert_eq!(size_of::<LeafNode<(), ()>>(), 16);
+    assert_eq!(size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8);
+    assert_eq!(size_of::<InternalNode<(), ()>>(), 16 + (CAPACITY + 1) * 8);
+    assert_eq!(size_of::<InternalNode<i64, i64>>(), 16 + (CAPACITY * 3 + 1) * 8);
 }
diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs
index 020cf4d7365..fac4d1a65ab 100644
--- a/library/alloc/src/collections/mod.rs
+++ b/library/alloc/src/collections/mod.rs
@@ -1,5 +1,8 @@
 //! Collection types.
 
+// Note: This module is also included in the alloctests crate using #[path] to
+// run the tests. See the comment there for an explanation why this is the case.
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[cfg(not(no_global_oom_handling))]
@@ -24,41 +27,54 @@ pub mod btree_map {
 pub mod btree_set {
     //! An ordered set based on a B-Tree.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(not(test))]
     pub use super::btree::set::*;
 }
 
+#[cfg(not(test))]
 use core::fmt::Display;
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use binary_heap::BinaryHeap;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use btree_map::BTreeMap;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use btree_set::BTreeSet;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use linked_list::LinkedList;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use vec_deque::VecDeque;
 
+#[cfg(not(test))]
 use crate::alloc::{Layout, LayoutError};
 
 /// The error type for `try_reserve` methods.
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "try_reserve", since = "1.57.0")]
+#[cfg(not(test))]
 pub struct TryReserveError {
     kind: TryReserveErrorKind,
 }
 
+#[cfg(test)]
+pub use realalloc::collections::TryReserveError;
+
+#[cfg(not(test))]
 impl TryReserveError {
     /// Details about the allocation that caused the error
     #[inline]
@@ -80,6 +96,7 @@ impl TryReserveError {
     reason = "Uncertain how much info should be exposed",
     issue = "48043"
 )]
+#[cfg(not(test))]
 pub enum TryReserveErrorKind {
     /// Error due to the computed capacity exceeding the collection's maximum
     /// (usually `isize::MAX` bytes).
@@ -103,11 +120,15 @@ pub enum TryReserveErrorKind {
     },
 }
 
+#[cfg(test)]
+pub use realalloc::collections::TryReserveErrorKind;
+
 #[unstable(
     feature = "try_reserve_kind",
     reason = "Uncertain how much info should be exposed",
     issue = "48043"
 )]
+#[cfg(not(test))]
 impl From<TryReserveErrorKind> for TryReserveError {
     #[inline]
     fn from(kind: TryReserveErrorKind) -> Self {
@@ -116,6 +137,7 @@ impl From<TryReserveErrorKind> for TryReserveError {
 }
 
 #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")]
+#[cfg(not(test))]
 impl From<LayoutError> for TryReserveErrorKind {
     /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
     #[inline]
@@ -125,6 +147,7 @@ impl From<LayoutError> for TryReserveErrorKind {
 }
 
 #[stable(feature = "try_reserve", since = "1.57.0")]
+#[cfg(not(test))]
 impl Display for TryReserveError {
     fn fmt(
         &self,
@@ -152,4 +175,5 @@ trait SpecExtend<I: IntoIterator> {
 }
 
 #[stable(feature = "try_reserve", since = "1.57.0")]
+#[cfg(not(test))]
 impl core::error::Error for TryReserveError {}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 299c8b8679e..f8844e2d3a5 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -645,6 +645,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// initialized rather than only supporting `0..len`.  Requires that
     /// `initialized.start` ≤ `initialized.end` ≤ `capacity`.
     #[inline]
+    #[cfg(not(test))]
     pub(crate) unsafe fn from_contiguous_raw_parts_in(
         ptr: *mut T,
         initialized: Range<usize>,
diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs
index d246385ca84..7c7072c4c3a 100644
--- a/library/alloc/src/collections/vec_deque/spec_extend.rs
+++ b/library/alloc/src/collections/vec_deque/spec_extend.rs
@@ -3,6 +3,7 @@ use core::slice;
 
 use super::VecDeque;
 use crate::alloc::Allocator;
+#[cfg(not(test))]
 use crate::vec;
 
 // Specialization trait used for VecDeque::extend
@@ -78,6 +79,7 @@ where
     }
 }
 
+#[cfg(not(test))]
 impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
     #[track_caller]
     fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) {
diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs
index 1efe84d6d7d..c80a30c2103 100644
--- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs
+++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs
@@ -19,6 +19,7 @@ where
     }
 }
 
+#[cfg(not(test))]
 impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> {
     #[inline]
     fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self {
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index fd93045a5ac..f6743c65710 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -10,7 +10,6 @@ use core::{fmt, mem, ops, ptr, slice};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::rc::Rc;
-use crate::slice::hack::into_vec;
 use crate::string::String;
 #[cfg(target_has_atomic = "ptr")]
 use crate::sync::Arc;
@@ -103,7 +102,7 @@ use crate::vec::Vec;
 /// of `CString` instances can lead to invalid memory accesses, memory leaks,
 /// and other memory errors.
 #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")]
+#[rustc_diagnostic_item = "cstring_type"]
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
 pub struct CString {
     // Invariant 1: the slice ends with a zero byte and has a length of at least one.
@@ -491,7 +490,7 @@ impl CString {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_bytes(self) -> Vec<u8> {
-        let mut vec = into_vec(self.into_inner());
+        let mut vec = self.into_inner().into_vec();
         let _nul = vec.pop();
         debug_assert_eq!(_nul, Some(0u8));
         vec
@@ -512,7 +511,7 @@ impl CString {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_bytes_with_nul(self) -> Vec<u8> {
-        into_vec(self.into_inner())
+        self.into_inner().into_vec()
     }
 
     /// Returns the contents of this `CString` as a slice of bytes.
@@ -573,7 +572,7 @@ impl CString {
     #[inline]
     #[must_use]
     #[stable(feature = "as_c_str", since = "1.20.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")]
+    #[rustc_diagnostic_item = "cstring_as_c_str"]
     pub fn as_c_str(&self) -> &CStr {
         &*self
     }
@@ -755,7 +754,6 @@ impl<'a> From<Cow<'a, CStr>> for CString {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "box_from_c_str", since = "1.17.0")]
 impl From<&CStr> for Box<CStr> {
     /// Converts a `&CStr` into a `Box<CStr>`,
@@ -766,7 +764,6 @@ impl From<&CStr> for Box<CStr> {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "box_from_mut_slice", since = "1.84.0")]
 impl From<&mut CStr> for Box<CStr> {
     /// Converts a `&mut CStr` into a `Box<CStr>`,
@@ -845,7 +842,6 @@ impl TryFrom<CString> for String {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "more_box_slice_clone", since = "1.29.0")]
 impl Clone for Box<CStr> {
     #[inline]
@@ -971,7 +967,6 @@ impl Default for Rc<CStr> {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<CStr> {
     fn default() -> Box<CStr> {
@@ -1080,7 +1075,7 @@ impl ToOwned for CStr {
     }
 
     fn clone_into(&self, target: &mut CString) {
-        let mut b = into_vec(mem::take(&mut target.inner));
+        let mut b = mem::take(&mut target.inner).into_vec();
         self.to_bytes_with_nul().clone_into(&mut b);
         target.inner = b.into_boxed_slice();
     }
@@ -1113,7 +1108,6 @@ impl AsRef<CStr> for CString {
     }
 }
 
-#[cfg(not(test))]
 impl CStr {
     /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
     ///
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index cb93100f56c..f0cdb1e4e0f 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -56,6 +56,7 @@
 //! [`Rc`]: rc
 //! [`RefCell`]: core::cell
 
+#![allow(incomplete_features)]
 #![allow(unused_attributes)]
 #![stable(feature = "alloc", since = "1.36.0")]
 #![doc(
@@ -92,7 +93,6 @@
 //
 // Library features:
 // tidy-alphabetical-start
-#![cfg_attr(test, feature(str_as_str))]
 #![feature(alloc_layout_extra)]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
@@ -113,6 +113,7 @@
 #![feature(deprecated_suggestion)]
 #![feature(deref_pure_trait)]
 #![feature(dispatch_from_dyn)]
+#![feature(ergonomic_clones)]
 #![feature(error_generic_member_access)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
@@ -159,13 +160,11 @@
 //
 // Language features:
 // tidy-alphabetical-start
-#![cfg_attr(not(test), feature(coroutine_trait))]
-#![cfg_attr(test, feature(panic_update_hook))]
-#![cfg_attr(test, feature(test))]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
 #![feature(cfg_sanitize)]
 #![feature(const_precise_live_drops)]
+#![feature(coroutine_trait)]
 #![feature(decl_macro)]
 #![feature(dropck_eyepatch)]
 #![feature(fundamental)]
@@ -198,15 +197,6 @@
 // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
 #![feature(intra_doc_pointers)]
 
-// Allow testing this library
-#[cfg(test)]
-#[macro_use]
-extern crate std;
-#[cfg(test)]
-extern crate test;
-#[cfg(test)]
-mod testing;
-
 // Module with internal macros used by other modules (needs to be included before other modules).
 #[macro_use]
 mod macros;
@@ -214,7 +204,6 @@ mod macros;
 mod raw_vec;
 
 // Heaps provided for low-level allocation strategies
-
 pub mod alloc;
 
 // Primitive types using the heaps above
@@ -222,13 +211,8 @@ pub mod alloc;
 // Need to conditionally define the mod from `boxed.rs` to avoid
 // duplicating the lang-items when building in test cfg; but also need
 // to allow code to have `use boxed::Box;` declarations.
-#[cfg(not(test))]
-pub mod boxed;
-#[cfg(test)]
-mod boxed {
-    pub(crate) use std::boxed::Box;
-}
 pub mod borrow;
+pub mod boxed;
 #[unstable(feature = "bstr", issue = "134915")]
 pub mod bstr;
 pub mod collections;
@@ -252,20 +236,3 @@ pub mod __export {
     pub use core::format_args;
     pub use core::hint::must_use;
 }
-
-#[cfg(test)]
-#[allow(dead_code)] // Not used in all configurations
-pub(crate) mod test_helpers {
-    /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
-    /// seed not being the same for every RNG invocation too.
-    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
-        use std::hash::{BuildHasher, Hash, Hasher};
-        let mut hasher = std::hash::RandomState::new().build_hasher();
-        std::panic::Location::caller().hash(&mut hasher);
-        let hc64 = hasher.finish();
-        let seed_vec =
-            hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
-        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
-        rand::SeedableRng::from_seed(seed)
-    }
-}
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index c000fd6f4ef..214192b8c9a 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -34,7 +34,7 @@
 /// be mindful of side effects.
 ///
 /// [`Vec`]: crate::vec::Vec
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "vec_macro"]
@@ -55,25 +55,6 @@ macro_rules! vec {
     );
 }
 
-// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
-// required for this macro definition, is not available. Instead use the
-// `slice::into_vec`  function which is only available with cfg(test)
-// NB see the slice::hack module in slice.rs for more information
-#[cfg(all(not(no_global_oom_handling), test))]
-#[allow(unused_macro_rules)]
-macro_rules! vec {
-    () => (
-        $crate::vec::Vec::new()
-    );
-    ($elem:expr; $n:expr) => (
-        $crate::vec::from_elem($elem, $n)
-    );
-    ($($x:expr),*) => (
-        $crate::slice::into_vec($crate::boxed::Box::new([$($x),*]))
-    );
-    ($($x:expr,)*) => (vec![$($x),*])
-}
-
 /// Creates a `String` using interpolation of runtime expressions.
 ///
 /// The first argument `format!` receives is a format string. This must be a string
@@ -120,7 +101,7 @@ macro_rules! vec {
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable(hint_must_use, liballoc_internals)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")]
+#[rustc_diagnostic_item = "format_macro"]
 macro_rules! format {
     ($($arg:tt)*) => {
         $crate::__export::must_use({
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec/mod.rs
index b80d1fc7889..99ebc5c4bfc 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec/mod.rs
@@ -1,4 +1,8 @@
 #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
+#![cfg_attr(test, allow(dead_code))]
+
+// Note: This module is also included in the alloctests crate using #[path] to
+// run the tests. See the comment there for an explanation why this is the case.
 
 use core::marker::PhantomData;
 use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
@@ -480,7 +484,7 @@ impl<A: Allocator> RawVecInner<A> {
 
         // Allocators currently return a `NonNull<[u8]>` whose length
         // matches the size requested. If that ever changes, the capacity
-        // here should change to `ptr.len() / mem::size_of::<T>()`.
+        // here should change to `ptr.len() / size_of::<T>()`.
         Ok(Self {
             ptr: Unique::from(ptr.cast()),
             cap: unsafe { Cap::new_unchecked(capacity) },
@@ -627,7 +631,7 @@ impl<A: Allocator> RawVecInner<A> {
     unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
         // Allocators currently return a `NonNull<[u8]>` whose length matches
         // the size requested. If that ever changes, the capacity here should
-        // change to `ptr.len() / mem::size_of::<T>()`.
+        // change to `ptr.len() / size_of::<T>()`.
         self.ptr = Unique::from(ptr.cast());
         self.cap = unsafe { Cap::new_unchecked(cap) };
     }
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs
index d78ded104fb..700fa922739 100644
--- a/library/alloc/src/raw_vec/tests.rs
+++ b/library/alloc/src/raw_vec/tests.rs
@@ -1,4 +1,3 @@
-use core::mem::size_of;
 use std::cell::Cell;
 
 use super::*;
@@ -93,7 +92,7 @@ fn zst_sanity<T>(v: &RawVec<T>) {
 fn zst() {
     let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into());
 
-    assert_eq!(std::mem::size_of::<ZST>(), 0);
+    assert_eq!(size_of::<ZST>(), 0);
 
     // All these different ways of creating the RawVec produce the same thing.
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 09206c2f8b2..fc1cee28d03 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -245,6 +245,7 @@ use core::any::Any;
 use core::cell::Cell;
 #[cfg(not(no_global_oom_handling))]
 use core::clone::CloneToUninit;
+use core::clone::UseCloned;
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
@@ -262,23 +263,17 @@ use core::ptr::{self, NonNull, drop_in_place};
 #[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
 use core::{borrow, fmt, hint};
-#[cfg(test)]
-use std::boxed::Box;
 
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::handle_alloc_error;
 use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
-#[cfg(not(test))]
 use crate::boxed::Box;
 #[cfg(not(no_global_oom_handling))]
 use crate::string::String;
 #[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
-#[cfg(test)]
-mod tests;
-
 // This is repr(C) to future-proof against possible field-reordering, which
 // would interfere with otherwise safe [into|from]_raw() of transmutable
 // inner types.
@@ -309,7 +304,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout {
 ///
 /// [get_mut]: Rc::get_mut
 #[doc(search_unbox)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
+#[rustc_diagnostic_item = "Rc"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_insignificant_dtor]
 pub struct Rc<
@@ -2333,6 +2328,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {}
+
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Default> Default for Rc<T> {
@@ -2984,7 +2982,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
 ///
 /// [`upgrade`]: Weak::upgrade
 #[stable(feature = "rc_weak", since = "1.4.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")]
+#[rustc_diagnostic_item = "RcWeak"]
 pub struct Weak<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
@@ -3496,6 +3494,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
+
 #[stable(feature = "rc_weak", since = "1.4.0")]
 impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index dcd95ddf00f..7c5d22e1ee9 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -8,15 +8,12 @@
 //! A few functions are provided to create a slice from a value reference
 //! or from a raw pointer.
 #![stable(feature = "rust1", since = "1.0.0")]
-// Many of the usings in this module are only used in the test configuration.
-// It's cleaner to just turn off the unused_imports warning than to fix them.
-#![cfg_attr(test, allow(unused_imports, dead_code))]
 
 use core::borrow::{Borrow, BorrowMut};
 #[cfg(not(no_global_oom_handling))]
 use core::cmp::Ordering::{self, Less};
 #[cfg(not(no_global_oom_handling))]
-use core::mem::{self, MaybeUninit};
+use core::mem::MaybeUninit;
 #[cfg(not(no_global_oom_handling))]
 use core::ptr;
 #[unstable(feature = "array_chunks", issue = "74985")]
@@ -63,16 +60,6 @@ pub use core::slice::{range, try_range};
 ////////////////////////////////////////////////////////////////////////////////
 // Basic slice extension methods
 ////////////////////////////////////////////////////////////////////////////////
-
-// HACK(japaric) needed for the implementation of `vec!` macro during testing
-// N.B., see the `hack` module in this file for more details.
-#[cfg(test)]
-pub use hack::into_vec;
-// HACK(japaric) needed for the implementation of `Vec::clone` during testing
-// N.B., see the `hack` module in this file for more details.
-#[cfg(test)]
-pub use hack::to_vec;
-
 use crate::alloc::Allocator;
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::Global;
@@ -81,98 +68,6 @@ use crate::borrow::ToOwned;
 use crate::boxed::Box;
 use crate::vec::Vec;
 
-// HACK(japaric): With cfg(test) `impl [T]` is not available, these three
-// functions are actually methods that are in `impl [T]` but not in
-// `core::slice::SliceExt` - we need to supply these functions for the
-// `test_permutations` test
-#[allow(unreachable_pub)] // cfg(test) pub above
-pub(crate) mod hack {
-    use core::alloc::Allocator;
-
-    use crate::boxed::Box;
-    use crate::vec::Vec;
-
-    // We shouldn't add inline attribute to this since this is used in
-    // `vec!` macro mostly and causes perf regression. See #71204 for
-    // discussion and perf results.
-    #[allow(missing_docs)]
-    pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> {
-        unsafe {
-            let len = b.len();
-            let (b, alloc) = Box::into_raw_with_allocator(b);
-            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
-        }
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    #[allow(missing_docs)]
-    #[inline]
-    pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> {
-        T::to_vec(s, alloc)
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    pub trait ConvertVec {
-        fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
-        where
-            Self: Sized;
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    impl<T: Clone> ConvertVec for T {
-        #[inline]
-        default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
-            struct DropGuard<'a, T, A: Allocator> {
-                vec: &'a mut Vec<T, A>,
-                num_init: usize,
-            }
-            impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
-                #[inline]
-                fn drop(&mut self) {
-                    // SAFETY:
-                    // items were marked initialized in the loop below
-                    unsafe {
-                        self.vec.set_len(self.num_init);
-                    }
-                }
-            }
-            let mut vec = Vec::with_capacity_in(s.len(), alloc);
-            let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
-            let slots = guard.vec.spare_capacity_mut();
-            // .take(slots.len()) is necessary for LLVM to remove bounds checks
-            // and has better codegen than zip.
-            for (i, b) in s.iter().enumerate().take(slots.len()) {
-                guard.num_init = i;
-                slots[i].write(b.clone());
-            }
-            core::mem::forget(guard);
-            // SAFETY:
-            // the vec was allocated and initialized above to at least this length.
-            unsafe {
-                vec.set_len(s.len());
-            }
-            vec
-        }
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    impl<T: Copy> ConvertVec for T {
-        #[inline]
-        fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
-            let mut v = Vec::with_capacity_in(s.len(), alloc);
-            // SAFETY:
-            // allocated above with the capacity of `s`, and initialize to `s.len()` in
-            // ptr::copy_to_non_overlapping below.
-            unsafe {
-                s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
-                v.set_len(s.len());
-            }
-            v
-        }
-    }
-}
-
-#[cfg(not(test))]
 impl<T> [T] {
     /// Sorts the slice, preserving initial order of equal elements.
     ///
@@ -446,7 +341,7 @@ impl<T> [T] {
         // Avoids binary-size usage in cases where the alignment doesn't work out to make this
         // beneficial or on 32-bit platforms.
         let is_using_u32_as_idx_type_helpful =
-            const { mem::size_of::<(K, u32)>() < mem::size_of::<(K, usize)>() };
+            const { size_of::<(K, u32)>() < size_of::<(K, usize)>() };
 
         // It's possible to instantiate this for u8 and u16 but, doing so is very wasteful in terms
         // of compile-times and binary-size, the peak saved heap memory for u16 is (u8 + u16) -> 4
@@ -501,8 +396,64 @@ impl<T> [T] {
     where
         T: Clone,
     {
-        // N.B., see the `hack` module in this file for more details.
-        hack::to_vec(self, alloc)
+        return T::to_vec(self, alloc);
+
+        trait ConvertVec {
+            fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
+            where
+                Self: Sized;
+        }
+
+        impl<T: Clone> ConvertVec for T {
+            #[inline]
+            default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
+                struct DropGuard<'a, T, A: Allocator> {
+                    vec: &'a mut Vec<T, A>,
+                    num_init: usize,
+                }
+                impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
+                    #[inline]
+                    fn drop(&mut self) {
+                        // SAFETY:
+                        // items were marked initialized in the loop below
+                        unsafe {
+                            self.vec.set_len(self.num_init);
+                        }
+                    }
+                }
+                let mut vec = Vec::with_capacity_in(s.len(), alloc);
+                let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
+                let slots = guard.vec.spare_capacity_mut();
+                // .take(slots.len()) is necessary for LLVM to remove bounds checks
+                // and has better codegen than zip.
+                for (i, b) in s.iter().enumerate().take(slots.len()) {
+                    guard.num_init = i;
+                    slots[i].write(b.clone());
+                }
+                core::mem::forget(guard);
+                // SAFETY:
+                // the vec was allocated and initialized above to at least this length.
+                unsafe {
+                    vec.set_len(s.len());
+                }
+                vec
+            }
+        }
+
+        impl<T: Copy> ConvertVec for T {
+            #[inline]
+            fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
+                let mut v = Vec::with_capacity_in(s.len(), alloc);
+                // SAFETY:
+                // allocated above with the capacity of `s`, and initialize to `s.len()` in
+                // ptr::copy_to_non_overlapping below.
+                unsafe {
+                    s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
+                    v.set_len(s.len());
+                }
+                v
+            }
+        }
     }
 
     /// Converts `self` into a vector without clones or allocation.
@@ -522,10 +473,13 @@ impl<T> [T] {
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")]
+    #[rustc_diagnostic_item = "slice_into_vec"]
     pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
-        // N.B., see the `hack` module in this file for more details.
-        hack::into_vec(self)
+        unsafe {
+            let len = self.len();
+            let (b, alloc) = Box::into_raw_with_allocator(self);
+            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
+        }
     }
 
     /// Creates a vector by copying a slice `n` times.
@@ -666,7 +620,6 @@ impl<T> [T] {
     }
 }
 
-#[cfg(not(test))]
 impl [u8] {
     /// Returns a vector containing a copy of this slice where each byte
     /// is mapped to its ASCII upper case equivalent.
@@ -883,14 +836,9 @@ impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> ToOwned for [T] {
     type Owned = Vec<T>;
-    #[cfg(not(test))]
-    fn to_owned(&self) -> Vec<T> {
-        self.to_vec()
-    }
 
-    #[cfg(test)]
     fn to_owned(&self) -> Vec<T> {
-        hack::to_vec(self, Global)
+        self.to_vec()
     }
 
     fn clone_into(&self, target: &mut Vec<T>) {
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 6fee8d3fe33..0664f2c3cf2 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -219,7 +219,6 @@ impl ToOwned for str {
 }
 
 /// Methods for string slices.
-#[cfg(not(test))]
 impl str {
     /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
     ///
@@ -631,7 +630,6 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
 #[unstable(feature = "str_internals", issue = "none")]
 #[doc(hidden)]
 #[inline]
-#[cfg(not(test))]
 #[cfg(not(no_global_oom_handling))]
 pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
     // Process the input in chunks of 16 bytes to enable auto-vectorization.
@@ -704,7 +702,6 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
     }
 }
 #[inline]
-#[cfg(not(test))]
 #[cfg(not(no_global_oom_handling))]
 #[allow(dead_code)]
 /// Faster implementation of string replacement for ASCII to ASCII cases.
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index fc4b93ccf8c..9236f5cb8d1 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -119,8 +119,6 @@ use crate::vec::{self, Vec};
 /// the same `char`s:
 ///
 /// ```
-/// use std::mem;
-///
 /// // `s` is ASCII which represents each `char` as one byte
 /// let s = "hello";
 /// assert_eq!(s.len(), 5);
@@ -128,7 +126,7 @@ use crate::vec::{self, Vec};
 /// // A `char` array with the same contents would be longer because
 /// // every `char` is four bytes
 /// let s = ['h', 'e', 'l', 'l', 'o'];
-/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
+/// let size: usize = s.into_iter().map(|c| size_of_val(&c)).sum();
 /// assert_eq!(size, 20);
 ///
 /// // However, for non-ASCII strings, the difference will be smaller
@@ -137,7 +135,7 @@ use crate::vec::{self, Vec};
 /// assert_eq!(s.len(), 20);
 ///
 /// let s = ['💖', '💖', '💖', '💖', '💖'];
-/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
+/// let size: usize = s.into_iter().map(|c| size_of_val(&c)).sum();
 /// assert_eq!(size, 20);
 /// ```
 ///
@@ -358,7 +356,7 @@ use crate::vec::{self, Vec};
 /// [`as_str()`]: String::as_str
 #[derive(PartialEq, PartialOrd, Eq, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), lang = "String")]
+#[lang = "String"]
 pub struct String {
     vec: Vec<u8>,
 }
@@ -440,7 +438,7 @@ impl String {
     /// ```
     #[inline]
     #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_new")]
+    #[rustc_diagnostic_item = "string_new"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub const fn new() -> String {
@@ -503,17 +501,6 @@ impl String {
         Ok(String { vec: Vec::try_with_capacity(capacity)? })
     }
 
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Since we don't
-    // require this method for testing purposes, I'll just stub it
-    // NB see the slice::hack module in slice.rs for more information
-    #[inline]
-    #[cfg(test)]
-    #[allow(missing_docs)]
-    pub fn from_str(_: &str) -> String {
-        panic!("not available with cfg(test)");
-    }
-
     /// Converts a vector of bytes to a `String`.
     ///
     /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
@@ -572,7 +559,7 @@ impl String {
     /// [`into_bytes`]: String::into_bytes
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")]
+    #[rustc_diagnostic_item = "string_from_utf8"]
     pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
         match str::from_utf8(&vec) {
             Ok(..) => Ok(String { vec }),
@@ -1056,7 +1043,8 @@ impl String {
     #[inline]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
     pub const fn into_bytes(self) -> Vec<u8> {
         self.vec
     }
@@ -1073,8 +1061,8 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_diagnostic_item = "string_as_str"]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn as_str(&self) -> &str {
         // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
         // at construction.
@@ -1096,8 +1084,8 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_diagnostic_item = "string_as_mut_str"]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn as_mut_str(&mut self) -> &mut str {
         // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
         // at construction.
@@ -1119,7 +1107,7 @@ impl String {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_confusables("append", "push")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")]
+    #[rustc_diagnostic_item = "string_push_str"]
     pub fn push_str(&mut self, string: &str) {
         self.vec.extend_from_slice(string.as_bytes())
     }
@@ -1171,7 +1159,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn capacity(&self) -> usize {
         self.vec.capacity()
     }
@@ -1437,7 +1425,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn as_bytes(&self) -> &[u8] {
         self.vec.as_slice()
     }
@@ -1757,7 +1745,7 @@ impl String {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "insert_str", since = "1.16.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")]
+    #[rustc_diagnostic_item = "string_insert_str"]
     pub fn insert_str(&mut self, idx: usize, string: &str) {
         assert!(self.is_char_boundary(idx));
 
@@ -1791,7 +1779,7 @@ impl String {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
         &mut self.vec
     }
@@ -1813,7 +1801,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_confusables("length", "size")]
     pub const fn len(&self) -> usize {
         self.vec.len()
@@ -1833,7 +1821,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -2726,7 +2714,7 @@ impl FromStr for String {
 /// implementation for free.
 ///
 /// [`Display`]: fmt::Display
-#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")]
+#[rustc_diagnostic_item = "ToString"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ToString {
     /// Converts the given value to a `String`.
@@ -2741,7 +2729,7 @@ pub trait ToString {
     /// ```
     #[rustc_conversion_suggestion]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")]
+    #[rustc_diagnostic_item = "to_string_method"]
     fn to_string(&self) -> String;
 }
 
@@ -2981,7 +2969,6 @@ impl From<&String> for String {
 }
 
 // note: test pulls in std, which causes errors here
-#[cfg(not(test))]
 #[stable(feature = "string_from_box", since = "1.18.0")]
 impl From<Box<str>> for String {
     /// Converts the given boxed `str` slice to a [`String`].
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index dba1449347a..4999319f618 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -11,6 +11,7 @@
 use core::any::Any;
 #[cfg(not(no_global_oom_handling))]
 use core::clone::CloneToUninit;
+use core::clone::UseCloned;
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
@@ -234,7 +235,7 @@ macro_rules! acquire {
 ///
 /// [rc_examples]: crate::rc#examples
 #[doc(search_unbox)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
+#[rustc_diagnostic_item = "Arc"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_insignificant_dtor]
 pub struct Arc<
@@ -311,7 +312,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
 ///
 /// [`upgrade`]: Weak::upgrade
 #[stable(feature = "arc_weak", since = "1.4.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "ArcWeak")]
+#[rustc_diagnostic_item = "ArcWeak"]
 pub struct Weak<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
@@ -2197,6 +2198,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
     type Target = T;
@@ -2274,7 +2278,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Arc<T, A> {
     #[inline]
     #[stable(feature = "arc_unique", since = "1.4.0")]
     pub fn make_mut(this: &mut Self) -> &mut T {
-        let size_of_val = mem::size_of_val::<T>(&**this);
+        let size_of_val = size_of_val::<T>(&**this);
 
         // Note that we hold both a strong reference and a weak reference.
         // Thus, releasing our strong reference only will not, by itself, cause
@@ -3158,6 +3162,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
+
 #[stable(feature = "downgraded_weak", since = "1.10.0")]
 impl<T> Default for Weak<T> {
     /// Constructs a new `Weak<T>`, without allocating memory.
@@ -3544,7 +3551,7 @@ impl<T> Default for Arc<[T]> {
     /// This may or may not share an allocation with other Arcs.
     #[inline]
     fn default() -> Self {
-        if mem::align_of::<T>() <= MAX_STATIC_INNER_SLICE_ALIGNMENT {
+        if align_of::<T>() <= MAX_STATIC_INNER_SLICE_ALIGNMENT {
             // We take a reference to the whole struct instead of the ArcInner<[u8; 1]> inside it so
             // we don't shrink the range of bytes the ptr is allowed to access under Stacked Borrows.
             // (Miri complains on 32-bit targets with Arc<[Align16]> otherwise.)
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index dffd85f13aa..b98a118048f 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -171,7 +171,7 @@ const fn in_place_collectible<DEST, SRC>(
 ) -> bool {
     // Require matching alignments because an alignment-changing realloc is inefficient on many
     // system allocators and better implementations would require the unstable Allocator trait.
-    if const { SRC::IS_ZST || DEST::IS_ZST || mem::align_of::<SRC>() != mem::align_of::<DEST>() } {
+    if const { SRC::IS_ZST || DEST::IS_ZST || align_of::<SRC>() != align_of::<DEST>() } {
         return false;
     }
 
@@ -181,7 +181,7 @@ const fn in_place_collectible<DEST, SRC>(
             // e.g.
             // - 1 x [u8; 4] -> 4x u8, via flatten
             // - 4 x u8 -> 1x [u8; 4], via array_chunks
-            mem::size_of::<SRC>() * step_merge.get() >= mem::size_of::<DEST>() * step_expand.get()
+            size_of::<SRC>() * step_merge.get() >= size_of::<DEST>() * step_expand.get()
         }
         // Fall back to other from_iter impls if an overflow occurred in the step merge/expansion
         // tracking.
@@ -190,7 +190,7 @@ const fn in_place_collectible<DEST, SRC>(
 }
 
 const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool {
-    if const { mem::align_of::<SRC>() != mem::align_of::<DEST>() } {
+    if const { align_of::<SRC>() != align_of::<DEST>() } {
         // FIXME(const-hack): use unreachable! once that works in const
         panic!("in_place_collectible() prevents this");
     }
@@ -199,8 +199,8 @@ const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool {
     // the caller will have calculated a `dst_cap` that is an integer multiple of
     // `src_cap` without remainder.
     if const {
-        let src_sz = mem::size_of::<SRC>();
-        let dest_sz = mem::size_of::<DEST>();
+        let src_sz = size_of::<SRC>();
+        let dest_sz = size_of::<DEST>();
         dest_sz != 0 && src_sz % dest_sz == 0
     } {
         return false;
@@ -208,7 +208,7 @@ const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool {
 
     // type layouts don't guarantee a fit, so do a runtime check to see if
     // the allocations happen to match
-    src_cap > 0 && src_cap * mem::size_of::<SRC>() != dst_cap * mem::size_of::<DEST>()
+    src_cap > 0 && src_cap * size_of::<SRC>() != dst_cap * size_of::<DEST>()
 }
 
 /// This provides a shorthand for the source type since local type aliases aren't a thing.
@@ -262,7 +262,7 @@ where
             inner.buf.cast::<T>(),
             inner.end as *const T,
             // SAFETY: the multiplication can not overflow, since `inner.cap * size_of::<I::SRC>()` is the size of the allocation.
-            inner.cap.unchecked_mul(mem::size_of::<I::Src>()) / mem::size_of::<T>(),
+            inner.cap.unchecked_mul(size_of::<I::Src>()) / size_of::<T>(),
         )
     };
 
@@ -310,14 +310,14 @@ where
         debug_assert_ne!(dst_cap, 0);
         unsafe {
             // The old allocation exists, therefore it must have a valid layout.
-            let src_align = mem::align_of::<I::Src>();
-            let src_size = mem::size_of::<I::Src>().unchecked_mul(src_cap);
+            let src_align = align_of::<I::Src>();
+            let src_size = size_of::<I::Src>().unchecked_mul(src_cap);
             let old_layout = Layout::from_size_align_unchecked(src_size, src_align);
 
             // The allocation must be equal or smaller for in-place iteration to be possible
             // therefore the new layout must be ≤ the old one and therefore valid.
-            let dst_align = mem::align_of::<T>();
-            let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap);
+            let dst_align = align_of::<T>();
+            let dst_size = size_of::<T>().unchecked_mul(dst_cap);
             let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align);
 
             let result = alloc.shrink(dst_buf.cast(), old_layout, new_layout);
@@ -325,7 +325,7 @@ where
             dst_buf = reallocated.cast::<T>();
         }
     } else {
-        debug_assert_eq!(src_cap * mem::size_of::<I::Src>(), dst_cap * mem::size_of::<T>());
+        debug_assert_eq!(src_cap * size_of::<I::Src>(), dst_cap * size_of::<T>());
     }
 
     mem::forget(dst_guard);
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 52597e41c1c..3eee988b6c9 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -472,14 +472,9 @@ where
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
-    #[cfg(not(test))]
     fn clone(&self) -> Self {
         self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter()
     }
-    #[cfg(test)]
-    fn clone(&self) -> Self {
-        crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter()
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 701144cc3af..da9a77154f9 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -293,7 +293,7 @@ mod spec_extend;
 /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
 /// types inside a `Vec`, it will not allocate space for them. *Note that in this case
 /// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only
-/// if <code>[mem::size_of::\<T>]\() * [capacity]\() > 0</code>. In general, `Vec`'s allocation
+/// if <code>[size_of::\<T>]\() * [capacity]\() > 0</code>. In general, `Vec`'s allocation
 /// details are very subtle --- if you intend to allocate memory using a `Vec`
 /// and use it for something else (either to pass to unsafe code, or to build your
 /// own memory-backed collection), be sure to deallocate this memory by using
@@ -393,7 +393,7 @@ mod spec_extend;
 /// [capacity]: Vec::capacity
 /// [`capacity`]: Vec::capacity
 /// [`Vec::capacity`]: Vec::capacity
-/// [mem::size_of::\<T>]: core::mem::size_of
+/// [size_of::\<T>]: size_of
 /// [len]: Vec::len
 /// [`len`]: Vec::len
 /// [`push`]: Vec::push
@@ -404,7 +404,7 @@ mod spec_extend;
 /// [owned slice]: Box
 /// [`into_boxed_slice`]: Vec::into_boxed_slice
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")]
+#[rustc_diagnostic_item = "Vec"]
 #[rustc_insignificant_dtor]
 pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
     buf: RawVec<T, A>,
@@ -428,7 +428,7 @@ impl<T> Vec<T> {
     /// ```
     #[inline]
     #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")]
+    #[rustc_diagnostic_item = "vec_new"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub const fn new() -> Self {
@@ -489,7 +489,7 @@ impl<T> Vec<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")]
+    #[rustc_diagnostic_item = "vec_with_capacity"]
     #[track_caller]
     pub fn with_capacity(capacity: usize) -> Self {
         Self::with_capacity_in(capacity, Global)
@@ -1254,7 +1254,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn capacity(&self) -> usize {
         self.buf.capacity()
     }
@@ -1279,7 +1279,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[track_caller]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")]
+    #[rustc_diagnostic_item = "vec_reserve"]
     pub fn reserve(&mut self, additional: usize) {
         self.buf.reserve(self.len, additional);
     }
@@ -1568,12 +1568,12 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_diagnostic_item = "vec_as_slice"]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn as_slice(&self) -> &[T] {
         // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
         // `len` containing properly-initialized `T`s. Data must not be mutated for the returned
-        // lifetime. Further, `len * mem::size_of::<T>` <= `ISIZE::MAX`, and allocation does not
+        // lifetime. Further, `len * size_of::<T>` <= `isize::MAX`, and allocation does not
         // "wrap" through overflowing memory addresses.
         //
         // * Vec API guarantees that self.buf:
@@ -1600,12 +1600,12 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_diagnostic_item = "vec_as_mut_slice"]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn as_mut_slice(&mut self) -> &mut [T] {
         // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
         // size `len` containing properly-initialized `T`s. Data must not be accessed through any
-        // other pointer for the returned lifetime. Further, `len * mem::size_of::<T>` <=
+        // other pointer for the returned lifetime. Further, `len * size_of::<T>` <=
         // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses.
         //
         // * Vec API guarantees that self.buf:
@@ -1673,7 +1673,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_never_returns_null_ptr]
     #[rustc_as_ptr]
     #[inline]
@@ -1736,7 +1736,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_never_returns_null_ptr]
     #[rustc_as_ptr]
     #[inline]
@@ -2511,7 +2511,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// Takes *O*(1) time.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")]
+    #[rustc_diagnostic_item = "vec_pop"]
     pub fn pop(&mut self) -> Option<T> {
         if self.len == 0 {
             None
@@ -2687,13 +2687,13 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_confusables("length", "size")]
     pub const fn len(&self) -> usize {
         let len = self.len;
 
         // SAFETY: The maximum capacity of `Vec<T>` is `isize::MAX` bytes, so the maximum value can
-        // be returned is `usize::checked_div(mem::size_of::<T>()).unwrap_or(usize::MAX)`, which
+        // be returned is `usize::checked_div(size_of::<T>()).unwrap_or(usize::MAX)`, which
         // matches the definition of `T::MAX_SLICE_LEN`.
         unsafe { intrinsics::assume(len <= T::MAX_SLICE_LEN) };
 
@@ -2712,8 +2712,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert!(!v.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
-    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    #[rustc_diagnostic_item = "vec_is_empty"]
+    #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -3193,7 +3193,7 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> {
 #[doc(hidden)]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")]
+#[rustc_diagnostic_item = "vec_from_elem"]
 #[track_caller]
 pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
     <T as SpecFromElem>::from_elem(elem, n, Global)
@@ -3293,23 +3293,12 @@ unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {}
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
-    #[cfg(not(test))]
     #[track_caller]
     fn clone(&self) -> Self {
         let alloc = self.allocator().clone();
         <[T]>::to_vec_in(&**self, alloc)
     }
 
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Instead use the
-    // `slice::to_vec` function which is only available with cfg(test)
-    // NB see the slice::hack module in slice.rs for more information
-    #[cfg(test)]
-    fn clone(&self) -> Self {
-        let alloc = self.allocator().clone();
-        crate::slice::to_vec(&**self, alloc)
-    }
-
     /// Overwrites the contents of `self` with a clone of the contents of `source`.
     ///
     /// This method is preferred over simply assigning `source.clone()` to `self`,
@@ -3854,15 +3843,10 @@ impl<T: Clone> From<&[T]> for Vec<T> {
     /// ```
     /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]);
     /// ```
-    #[cfg(not(test))]
     #[track_caller]
     fn from(s: &[T]) -> Vec<T> {
         s.to_vec()
     }
-    #[cfg(test)]
-    fn from(s: &[T]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
 }
 
 #[cfg(not(no_global_oom_handling))]
@@ -3875,15 +3859,10 @@ impl<T: Clone> From<&mut [T]> for Vec<T> {
     /// ```
     /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]);
     /// ```
-    #[cfg(not(test))]
     #[track_caller]
     fn from(s: &mut [T]) -> Vec<T> {
         s.to_vec()
     }
-    #[cfg(test)]
-    fn from(s: &mut [T]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
 }
 
 #[cfg(not(no_global_oom_handling))]
@@ -3928,16 +3907,10 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> {
     /// ```
     /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]);
     /// ```
-    #[cfg(not(test))]
     #[track_caller]
     fn from(s: [T; N]) -> Vec<T> {
         <[T]>::into_vec(Box::new(s))
     }
-
-    #[cfg(test)]
-    fn from(s: [T; N]) -> Vec<T> {
-        crate::slice::into_vec(Box::new(s))
-    }
 }
 
 #[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
@@ -3966,7 +3939,6 @@ where
 }
 
 // note: test pulls in std, which causes errors here
-#[cfg(not(test))]
 #[stable(feature = "vec_from_box", since = "1.18.0")]
 impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
     /// Converts a boxed slice into a vector by transferring ownership of
@@ -3985,7 +3957,6 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
 
 // note: test pulls in std, which causes errors here
 #[cfg(not(no_global_oom_handling))]
-#[cfg(not(test))]
 #[stable(feature = "box_from_vec", since = "1.20.0")]
 impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
     /// Converts a vector into a boxed slice.
diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs
deleted file mode 100644
index 451765d7242..00000000000
--- a/library/alloc/tests/rc.rs
+++ /dev/null
@@ -1,260 +0,0 @@
-use std::any::Any;
-use std::cell::{Cell, RefCell};
-use std::iter::TrustedLen;
-use std::mem;
-use std::rc::{Rc, Weak};
-
-#[test]
-fn uninhabited() {
-    enum Void {}
-    let mut a = Weak::<Void>::new();
-    a = a.clone();
-    assert!(a.upgrade().is_none());
-
-    let mut a: Weak<dyn Any> = a; // Unsizing
-    a = a.clone();
-    assert!(a.upgrade().is_none());
-}
-
-#[test]
-fn slice() {
-    let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]);
-    let a: Rc<[u32]> = a; // Unsizing
-    let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion
-    assert_eq!(a, b);
-
-    // Exercise is_dangling() with a DST
-    let mut a = Rc::downgrade(&a);
-    a = a.clone();
-    assert!(a.upgrade().is_some());
-}
-
-#[test]
-fn trait_object() {
-    let a: Rc<u32> = Rc::new(4);
-    let a: Rc<dyn Any> = a; // Unsizing
-
-    // Exercise is_dangling() with a DST
-    let mut a = Rc::downgrade(&a);
-    a = a.clone();
-    assert!(a.upgrade().is_some());
-
-    let mut b = Weak::<u32>::new();
-    b = b.clone();
-    assert!(b.upgrade().is_none());
-    let mut b: Weak<dyn Any> = b; // Unsizing
-    b = b.clone();
-    assert!(b.upgrade().is_none());
-}
-
-#[test]
-fn float_nan_ne() {
-    let x = Rc::new(f32::NAN);
-    assert!(x != x);
-    assert!(!(x == x));
-}
-
-#[test]
-fn partial_eq() {
-    struct TestPEq(RefCell<usize>);
-    impl PartialEq for TestPEq {
-        fn eq(&self, other: &TestPEq) -> bool {
-            *self.0.borrow_mut() += 1;
-            *other.0.borrow_mut() += 1;
-            true
-        }
-    }
-    let x = Rc::new(TestPEq(RefCell::new(0)));
-    assert!(x == x);
-    assert!(!(x != x));
-    assert_eq!(*x.0.borrow(), 4);
-}
-
-#[test]
-fn eq() {
-    #[derive(Eq)]
-    struct TestEq(RefCell<usize>);
-    impl PartialEq for TestEq {
-        fn eq(&self, other: &TestEq) -> bool {
-            *self.0.borrow_mut() += 1;
-            *other.0.borrow_mut() += 1;
-            true
-        }
-    }
-    let x = Rc::new(TestEq(RefCell::new(0)));
-    assert!(x == x);
-    assert!(!(x != x));
-    assert_eq!(*x.0.borrow(), 0);
-}
-
-const SHARED_ITER_MAX: u16 = 100;
-
-fn assert_trusted_len<I: TrustedLen>(_: &I) {}
-
-#[test]
-fn shared_from_iter_normal() {
-    // Exercise the base implementation for non-`TrustedLen` iterators.
-    {
-        // `Filter` is never `TrustedLen` since we don't
-        // know statically how many elements will be kept:
-        let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new);
-
-        // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
-        let vec = iter.clone().collect::<Vec<_>>();
-        let rc = iter.collect::<Rc<[_]>>();
-        assert_eq!(&*vec, &*rc);
-
-        // Clone a bit and let these get dropped.
-        {
-            let _rc_2 = rc.clone();
-            let _rc_3 = rc.clone();
-            let _rc_4 = Rc::downgrade(&_rc_3);
-        }
-    } // Drop what hasn't been here.
-}
-
-#[test]
-fn shared_from_iter_trustedlen_normal() {
-    // Exercise the `TrustedLen` implementation under normal circumstances
-    // where `size_hint()` matches `(_, Some(exact_len))`.
-    {
-        let iter = (0..SHARED_ITER_MAX).map(Box::new);
-        assert_trusted_len(&iter);
-
-        // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
-        let vec = iter.clone().collect::<Vec<_>>();
-        let rc = iter.collect::<Rc<[_]>>();
-        assert_eq!(&*vec, &*rc);
-        assert_eq!(mem::size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc));
-
-        // Clone a bit and let these get dropped.
-        {
-            let _rc_2 = rc.clone();
-            let _rc_3 = rc.clone();
-            let _rc_4 = Rc::downgrade(&_rc_3);
-        }
-    } // Drop what hasn't been here.
-
-    // Try a ZST to make sure it is handled well.
-    {
-        let iter = (0..SHARED_ITER_MAX).map(drop);
-        let vec = iter.clone().collect::<Vec<_>>();
-        let rc = iter.collect::<Rc<[_]>>();
-        assert_eq!(&*vec, &*rc);
-        assert_eq!(0, mem::size_of_val(&*rc));
-        {
-            let _rc_2 = rc.clone();
-            let _rc_3 = rc.clone();
-            let _rc_4 = Rc::downgrade(&_rc_3);
-        }
-    }
-}
-
-#[test]
-#[should_panic = "I've almost got 99 problems."]
-fn shared_from_iter_trustedlen_panic() {
-    // Exercise the `TrustedLen` implementation when `size_hint()` matches
-    // `(_, Some(exact_len))` but where `.next()` drops before the last iteration.
-    let iter = (0..SHARED_ITER_MAX).map(|val| match val {
-        98 => panic!("I've almost got 99 problems."),
-        _ => Box::new(val),
-    });
-    assert_trusted_len(&iter);
-    let _ = iter.collect::<Rc<[_]>>();
-
-    panic!("I am unreachable.");
-}
-
-#[test]
-fn shared_from_iter_trustedlen_no_fuse() {
-    // Exercise the `TrustedLen` implementation when `size_hint()` matches
-    // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner.
-    struct Iter(std::vec::IntoIter<Option<Box<u8>>>);
-
-    unsafe impl TrustedLen for Iter {}
-
-    impl Iterator for Iter {
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            (2, Some(2))
-        }
-
-        type Item = Box<u8>;
-
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next().flatten()
-        }
-    }
-
-    let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))];
-    let iter = Iter(vec.into_iter());
-    assert_trusted_len(&iter);
-    assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
-}
-
-#[test]
-fn weak_may_dangle() {
-    fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
-        val.clone()
-    }
-
-    // Without #[may_dangle] we get:
-    let mut val = Weak::new();
-    hmm(&mut val);
-    //  ~~~~~~~~ borrowed value does not live long enough
-    //
-    // `val` dropped here while still borrowed
-    // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
-}
-
-/// Test that a panic from a destructor does not leak the allocation.
-#[test]
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
-fn panic_no_leak() {
-    use std::alloc::{AllocError, Allocator, Global, Layout};
-    use std::panic::{AssertUnwindSafe, catch_unwind};
-    use std::ptr::NonNull;
-
-    struct AllocCount(Cell<i32>);
-    unsafe impl Allocator for AllocCount {
-        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
-            self.0.set(self.0.get() + 1);
-            Global.allocate(layout)
-        }
-        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
-            self.0.set(self.0.get() - 1);
-            unsafe { Global.deallocate(ptr, layout) }
-        }
-    }
-
-    struct PanicOnDrop;
-    impl Drop for PanicOnDrop {
-        fn drop(&mut self) {
-            panic!("PanicOnDrop");
-        }
-    }
-
-    let alloc = AllocCount(Cell::new(0));
-    let rc = Rc::new_in(PanicOnDrop, &alloc);
-    assert_eq!(alloc.0.get(), 1);
-
-    let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err();
-    assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
-    assert_eq!(alloc.0.get(), 0);
-}
-
-#[allow(unused)]
-mod pin_coerce_unsized {
-    use alloc::rc::{Rc, UniqueRc};
-    use core::pin::Pin;
-
-    pub trait MyTrait {}
-    impl MyTrait for String {}
-
-    // Pin coercion should work for Rc
-    pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> {
-        arg
-    }
-    pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> {
-        arg
-    }
-}
diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml
new file mode 100644
index 00000000000..306375f5f01
--- /dev/null
+++ b/library/alloctests/Cargo.toml
@@ -0,0 +1,47 @@
+[package]
+name = "alloctests"
+version = "0.0.0"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-lang/rust.git"
+description = "Tests for the Rust Allocation Library"
+autotests = false
+autobenches = false
+edition = "2021"
+
+[lib]
+path = "lib.rs"
+test = true
+bench = true
+doc = false
+
+[dev-dependencies]
+rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
+rand_xorshift = "0.4.0"
+
+[[test]]
+name = "alloctests"
+path = "tests/lib.rs"
+
+[[test]]
+name = "vec_deque_alloc_error"
+path = "tests/vec_deque_alloc_error.rs"
+
+[[bench]]
+name = "allocbenches"
+path = "benches/lib.rs"
+test = true
+
+[[bench]]
+name = "vec_deque_append_bench"
+path = "benches/vec_deque_append.rs"
+harness = false
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+    'cfg(bootstrap)',
+    'cfg(no_global_oom_handling)',
+    'cfg(no_rc)',
+    'cfg(no_sync)',
+    'cfg(randomized_layouts)',
+]
diff --git a/library/alloc/benches/binary_heap.rs b/library/alloctests/benches/binary_heap.rs
index 1b8f7f1c242..1b8f7f1c242 100644
--- a/library/alloc/benches/binary_heap.rs
+++ b/library/alloctests/benches/binary_heap.rs
diff --git a/library/alloc/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs
index 20f02dc3a96..20f02dc3a96 100644
--- a/library/alloc/benches/btree/map.rs
+++ b/library/alloctests/benches/btree/map.rs
diff --git a/library/alloc/benches/btree/mod.rs b/library/alloctests/benches/btree/mod.rs
index 095ca5dd2e2..095ca5dd2e2 100644
--- a/library/alloc/benches/btree/mod.rs
+++ b/library/alloctests/benches/btree/mod.rs
diff --git a/library/alloc/benches/btree/set.rs b/library/alloctests/benches/btree/set.rs
index 5aa395b4d52..5aa395b4d52 100644
--- a/library/alloc/benches/btree/set.rs
+++ b/library/alloctests/benches/btree/set.rs
diff --git a/library/alloc/benches/lib.rs b/library/alloctests/benches/lib.rs
index 2633154318c..2633154318c 100644
--- a/library/alloc/benches/lib.rs
+++ b/library/alloctests/benches/lib.rs
diff --git a/library/alloc/benches/linked_list.rs b/library/alloctests/benches/linked_list.rs
index b9322b6d4c3..b9322b6d4c3 100644
--- a/library/alloc/benches/linked_list.rs
+++ b/library/alloctests/benches/linked_list.rs
diff --git a/library/alloc/benches/slice.rs b/library/alloctests/benches/slice.rs
index c6b46e6a2a1..27b0e6fac0a 100644
--- a/library/alloc/benches/slice.rs
+++ b/library/alloctests/benches/slice.rs
@@ -1,4 +1,4 @@
-use std::{mem, ptr};
+use std::ptr;
 
 use rand::Rng;
 use rand::distr::{Alphanumeric, SampleString, StandardUniform};
@@ -234,7 +234,7 @@ macro_rules! sort {
         fn $name(b: &mut Bencher) {
             let v = $gen($len);
             b.iter(|| v.clone().$f());
-            b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64;
+            b.bytes = $len * size_of_val(&$gen(1)[0]) as u64;
         }
     };
 }
@@ -246,7 +246,7 @@ macro_rules! sort_strings {
             let v = $gen($len);
             let v = v.iter().map(|s| &**s).collect::<Vec<&str>>();
             b.iter(|| v.clone().$f());
-            b.bytes = $len * mem::size_of::<&str>() as u64;
+            b.bytes = $len * size_of::<&str>() as u64;
         }
     };
 }
@@ -268,7 +268,7 @@ macro_rules! sort_expensive {
                 });
                 black_box(count);
             });
-            b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64;
+            b.bytes = $len * size_of_val(&$gen(1)[0]) as u64;
         }
     };
 }
@@ -279,7 +279,7 @@ macro_rules! sort_lexicographic {
         fn $name(b: &mut Bencher) {
             let v = $gen($len);
             b.iter(|| v.clone().$f(|x| x.to_string()));
-            b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64;
+            b.bytes = $len * size_of_val(&$gen(1)[0]) as u64;
         }
     };
 }
@@ -322,7 +322,7 @@ macro_rules! reverse {
         fn $name(b: &mut Bencher) {
             // odd length and offset by 1 to be as unaligned as possible
             let n = 0xFFFFF;
-            let mut v: Vec<_> = (0..1 + (n / mem::size_of::<$ty>() as u64)).map($f).collect();
+            let mut v: Vec<_> = (0..1 + (n / size_of::<$ty>() as u64)).map($f).collect();
             b.iter(|| black_box(&mut v[1..]).reverse());
             b.bytes = n;
         }
@@ -346,7 +346,7 @@ macro_rules! rotate {
     ($name:ident, $gen:expr, $len:expr, $mid:expr) => {
         #[bench]
         fn $name(b: &mut Bencher) {
-            let size = mem::size_of_val(&$gen(1)[0]);
+            let size = size_of_val(&$gen(1)[0]);
             let mut v = $gen($len * 8 / size);
             b.iter(|| black_box(&mut v).rotate_left(($mid * 8 + size - 1) / size));
             b.bytes = (v.len() * size) as u64;
diff --git a/library/alloc/benches/str.rs b/library/alloctests/benches/str.rs
index 98c7c5413ca..98c7c5413ca 100644
--- a/library/alloc/benches/str.rs
+++ b/library/alloctests/benches/str.rs
diff --git a/library/alloc/benches/string.rs b/library/alloctests/benches/string.rs
index 3d79ab78c69..3d79ab78c69 100644
--- a/library/alloc/benches/string.rs
+++ b/library/alloctests/benches/string.rs
diff --git a/library/alloc/benches/vec.rs b/library/alloctests/benches/vec.rs
index a725ad6894b..1dab71fa1f4 100644
--- a/library/alloc/benches/vec.rs
+++ b/library/alloctests/benches/vec.rs
@@ -669,7 +669,7 @@ fn random_sorted_fill(mut seed: u32, buf: &mut [u32]) {
 // This algorithm was used for Vecs prior to Rust 1.52.
 fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) {
     let mut template = vec![0u32; sz];
-    b.bytes = std::mem::size_of_val(template.as_slice()) as u64;
+    b.bytes = size_of_val(template.as_slice()) as u64;
     random_sorted_fill(0x43, &mut template);
 
     let mut vec = template.clone();
@@ -691,7 +691,7 @@ fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) {
 // Measures performance of Vec::dedup on random data.
 fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) {
     let mut template = vec![0u32; sz];
-    b.bytes = std::mem::size_of_val(template.as_slice()) as u64;
+    b.bytes = size_of_val(template.as_slice()) as u64;
     random_sorted_fill(0x43, &mut template);
 
     let mut vec = template.clone();
@@ -708,7 +708,7 @@ fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) {
 // Measures performance of Vec::dedup when there is no items removed
 fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) {
     let mut template = vec![0u32; sz];
-    b.bytes = std::mem::size_of_val(template.as_slice()) as u64;
+    b.bytes = size_of_val(template.as_slice()) as u64;
     template.chunks_exact_mut(2).for_each(|w| {
         w[0] = black_box(0);
         w[1] = black_box(5);
@@ -729,7 +729,7 @@ fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) {
 // Measures performance of Vec::dedup when there is all items removed
 fn bench_vec_dedup_all(b: &mut Bencher, sz: usize) {
     let mut template = vec![0u32; sz];
-    b.bytes = std::mem::size_of_val(template.as_slice()) as u64;
+    b.bytes = size_of_val(template.as_slice()) as u64;
     template.iter_mut().for_each(|w| {
         *w = black_box(0);
     });
diff --git a/library/alloc/benches/vec_deque.rs b/library/alloctests/benches/vec_deque.rs
index a56f8496963..a56f8496963 100644
--- a/library/alloc/benches/vec_deque.rs
+++ b/library/alloctests/benches/vec_deque.rs
diff --git a/library/alloc/benches/vec_deque_append.rs b/library/alloctests/benches/vec_deque_append.rs
index 7c805da9737..7c805da9737 100644
--- a/library/alloc/benches/vec_deque_append.rs
+++ b/library/alloctests/benches/vec_deque_append.rs
diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs
new file mode 100644
index 00000000000..6ce8a6d9ca1
--- /dev/null
+++ b/library/alloctests/lib.rs
@@ -0,0 +1,93 @@
+#![cfg(test)]
+#![allow(unused_attributes)]
+#![unstable(feature = "alloctests", issue = "none")]
+#![no_std]
+// Lints:
+#![deny(unsafe_op_in_unsafe_fn)]
+#![warn(deprecated_in_future)]
+#![warn(missing_debug_implementations)]
+#![allow(explicit_outlives_requirements)]
+#![allow(internal_features)]
+#![allow(rustdoc::redundant_explicit_links)]
+#![warn(rustdoc::unescaped_backticks)]
+#![deny(ffi_unwind_calls)]
+//
+// Library features:
+// tidy-alphabetical-start
+#![feature(alloc_layout_extra)]
+#![feature(allocator_api)]
+#![feature(array_into_iter_constructors)]
+#![feature(assert_matches)]
+#![feature(core_intrinsics)]
+#![feature(exact_size_is_empty)]
+#![feature(extend_one)]
+#![feature(extend_one_unchecked)]
+#![feature(hasher_prefixfree_extras)]
+#![feature(inplace_iteration)]
+#![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
+#![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_uninit_array_transpose)]
+#![feature(ptr_internals)]
+#![feature(sized_type_properties)]
+#![feature(slice_iter_mut_as_mut_slice)]
+#![feature(slice_ptr_get)]
+#![feature(slice_range)]
+#![feature(std_internals)]
+#![feature(temporary_niche_types)]
+#![feature(trusted_fused)]
+#![feature(trusted_len)]
+#![feature(trusted_random_access)]
+#![feature(try_reserve_kind)]
+#![feature(try_trait_v2)]
+// tidy-alphabetical-end
+//
+// Language features:
+// tidy-alphabetical-start
+#![feature(cfg_sanitize)]
+#![feature(dropck_eyepatch)]
+#![feature(lang_items)]
+#![feature(min_specialization)]
+#![feature(negative_impls)]
+#![feature(never_type)]
+#![feature(optimize_attribute)]
+#![feature(rustc_allow_const_fn_unstable)]
+#![feature(rustc_attrs)]
+#![feature(staged_api)]
+#![feature(test)]
+#![rustc_preserve_ub_checks]
+// tidy-alphabetical-end
+
+// Allow testing this library
+extern crate alloc as realalloc;
+#[macro_use]
+extern crate std;
+#[cfg(test)]
+extern crate test;
+mod testing;
+use realalloc::*;
+
+// We are directly including collections and raw_vec here as both use non-public
+// methods and fields in tests and as such need to have the types to test in the
+// same crate as the tests themself.
+#[path = "../alloc/src/collections/mod.rs"]
+mod collections;
+
+#[path = "../alloc/src/raw_vec/mod.rs"]
+mod raw_vec;
+
+#[allow(dead_code)] // Not used in all configurations
+pub(crate) mod test_helpers {
+    /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+    /// seed not being the same for every RNG invocation too.
+    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+        use std::hash::{BuildHasher, Hash, Hasher};
+        let mut hasher = std::hash::RandomState::new().build_hasher();
+        std::panic::Location::caller().hash(&mut hasher);
+        let hc64 = hasher.finish();
+        let seed_vec =
+            hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
+        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+        rand::SeedableRng::from_seed(seed)
+    }
+}
diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloctests/testing/crash_test.rs
index 8e00e4f41e5..8e00e4f41e5 100644
--- a/library/alloc/src/testing/crash_test.rs
+++ b/library/alloctests/testing/crash_test.rs
diff --git a/library/alloc/src/testing/mod.rs b/library/alloctests/testing/mod.rs
index c8457daf93e..c8457daf93e 100644
--- a/library/alloc/src/testing/mod.rs
+++ b/library/alloctests/testing/mod.rs
diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs
index 55e1ae5e3de..55e1ae5e3de 100644
--- a/library/alloc/src/testing/ord_chaos.rs
+++ b/library/alloctests/testing/ord_chaos.rs
diff --git a/library/alloc/src/testing/rng.rs b/library/alloctests/testing/rng.rs
index 77d3348f38a..77d3348f38a 100644
--- a/library/alloc/src/testing/rng.rs
+++ b/library/alloctests/testing/rng.rs
diff --git a/library/alloc/tests/alloc.rs b/library/alloctests/tests/alloc_test.rs
index 1e722d66795..1e722d66795 100644
--- a/library/alloc/tests/alloc.rs
+++ b/library/alloctests/tests/alloc_test.rs
diff --git a/library/alloc/tests/arc.rs b/library/alloctests/tests/arc.rs
index a259c0131ec..0baa50f439b 100644
--- a/library/alloc/tests/arc.rs
+++ b/library/alloctests/tests/arc.rs
@@ -1,7 +1,6 @@
 use std::any::Any;
 use std::cell::{Cell, RefCell};
 use std::iter::TrustedLen;
-use std::mem;
 use std::sync::{Arc, Weak};
 
 #[test]
@@ -129,7 +128,7 @@ fn shared_from_iter_trustedlen_normal() {
         let vec = iter.clone().collect::<Vec<_>>();
         let rc = iter.collect::<Rc<[_]>>();
         assert_eq!(&*vec, &*rc);
-        assert_eq!(mem::size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc));
+        assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc));
 
         // Clone a bit and let these get dropped.
         {
@@ -145,7 +144,7 @@ fn shared_from_iter_trustedlen_normal() {
         let vec = iter.clone().collect::<Vec<_>>();
         let rc = iter.collect::<Rc<[_]>>();
         assert_eq!(&*vec, &*rc);
-        assert_eq!(0, mem::size_of_val(&*rc));
+        assert_eq!(0, size_of_val(&*rc));
         {
             let _rc_2 = rc.clone();
             let _rc_3 = rc.clone();
diff --git a/library/alloc/tests/autotraits.rs b/library/alloctests/tests/autotraits.rs
index 6b82deeac8a..6b82deeac8a 100644
--- a/library/alloc/tests/autotraits.rs
+++ b/library/alloctests/tests/autotraits.rs
diff --git a/library/alloc/tests/borrow.rs b/library/alloctests/tests/borrow.rs
index af7efb7d782..af7efb7d782 100644
--- a/library/alloc/tests/borrow.rs
+++ b/library/alloctests/tests/borrow.rs
diff --git a/library/alloc/tests/boxed.rs b/library/alloctests/tests/boxed.rs
index 94389cf2de9..94389cf2de9 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloctests/tests/boxed.rs
diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloctests/tests/btree_set_hash.rs
index 71a3a143209..71a3a143209 100644
--- a/library/alloc/tests/btree_set_hash.rs
+++ b/library/alloctests/tests/btree_set_hash.rs
diff --git a/library/alloc/tests/c_str.rs b/library/alloctests/tests/c_str.rs
index 4a581793956..4a581793956 100644
--- a/library/alloc/tests/c_str.rs
+++ b/library/alloctests/tests/c_str.rs
diff --git a/library/alloc/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs
index 0f4c27fa123..0f4c27fa123 100644
--- a/library/alloc/tests/c_str2.rs
+++ b/library/alloctests/tests/c_str2.rs
diff --git a/library/alloc/tests/collections/binary_heap.rs b/library/alloctests/tests/collections/binary_heap.rs
index 95f4c3e614f..95f4c3e614f 100644
--- a/library/alloc/tests/collections/binary_heap.rs
+++ b/library/alloctests/tests/collections/binary_heap.rs
diff --git a/library/alloc/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs
index e73f3aaef8c..e73f3aaef8c 100644
--- a/library/alloc/tests/collections/mod.rs
+++ b/library/alloctests/tests/collections/mod.rs
diff --git a/library/alloc/tests/const_fns.rs b/library/alloctests/tests/const_fns.rs
index 4e7d7fc833e..4e7d7fc833e 100644
--- a/library/alloc/tests/const_fns.rs
+++ b/library/alloctests/tests/const_fns.rs
diff --git a/library/alloc/tests/cow_str.rs b/library/alloctests/tests/cow_str.rs
index 62a5c245a54..62a5c245a54 100644
--- a/library/alloc/tests/cow_str.rs
+++ b/library/alloctests/tests/cow_str.rs
diff --git a/library/alloc/tests/fmt.rs b/library/alloctests/tests/fmt.rs
index c13074c53b7..c13074c53b7 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloctests/tests/fmt.rs
diff --git a/library/alloc/tests/heap.rs b/library/alloctests/tests/heap.rs
index 246b341eeb3..246b341eeb3 100644
--- a/library/alloc/tests/heap.rs
+++ b/library/alloctests/tests/heap.rs
diff --git a/library/alloc/tests/lib.rs b/library/alloctests/tests/lib.rs
index 785070fb2bb..46c11ea150b 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -43,11 +43,12 @@
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
+extern crate alloc;
 extern crate test;
 
 use std::hash::{DefaultHasher, Hash, Hasher};
 
-mod alloc;
+mod alloc_test;
 mod arc;
 mod autotraits;
 mod borrow;
diff --git a/library/alloc/tests/linked_list.rs b/library/alloctests/tests/linked_list.rs
index 65b09cb00c4..65b09cb00c4 100644
--- a/library/alloc/tests/linked_list.rs
+++ b/library/alloctests/tests/linked_list.rs
diff --git a/library/alloc/tests/misc_tests.rs b/library/alloctests/tests/misc_tests.rs
index b95d11cb07e..b95d11cb07e 100644
--- a/library/alloc/tests/misc_tests.rs
+++ b/library/alloctests/tests/misc_tests.rs
diff --git a/library/alloc/src/rc/tests.rs b/library/alloctests/tests/rc.rs
index 2210a7c24c0..bb68eb4ac9e 100644
--- a/library/alloc/src/rc/tests.rs
+++ b/library/alloctests/tests/rc.rs
@@ -1,7 +1,263 @@
-use std::cell::RefCell;
-use std::clone::Clone;
+use std::any::Any;
+use std::cell::{Cell, RefCell};
+use std::iter::TrustedLen;
+use std::mem;
+use std::rc::{Rc, UniqueRc, Weak};
 
-use super::*;
+#[test]
+fn uninhabited() {
+    enum Void {}
+    let mut a = Weak::<Void>::new();
+    a = a.clone();
+    assert!(a.upgrade().is_none());
+
+    let mut a: Weak<dyn Any> = a; // Unsizing
+    a = a.clone();
+    assert!(a.upgrade().is_none());
+}
+
+#[test]
+fn slice() {
+    let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]);
+    let a: Rc<[u32]> = a; // Unsizing
+    let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion
+    assert_eq!(a, b);
+
+    // Exercise is_dangling() with a DST
+    let mut a = Rc::downgrade(&a);
+    a = a.clone();
+    assert!(a.upgrade().is_some());
+}
+
+#[test]
+fn trait_object() {
+    let a: Rc<u32> = Rc::new(4);
+    let a: Rc<dyn Any> = a; // Unsizing
+
+    // Exercise is_dangling() with a DST
+    let mut a = Rc::downgrade(&a);
+    a = a.clone();
+    assert!(a.upgrade().is_some());
+
+    let mut b = Weak::<u32>::new();
+    b = b.clone();
+    assert!(b.upgrade().is_none());
+    let mut b: Weak<dyn Any> = b; // Unsizing
+    b = b.clone();
+    assert!(b.upgrade().is_none());
+}
+
+#[test]
+fn float_nan_ne() {
+    let x = Rc::new(f32::NAN);
+    assert!(x != x);
+    assert!(!(x == x));
+}
+
+#[test]
+fn partial_eq() {
+    struct TestPEq(RefCell<usize>);
+    impl PartialEq for TestPEq {
+        fn eq(&self, other: &TestPEq) -> bool {
+            *self.0.borrow_mut() += 1;
+            *other.0.borrow_mut() += 1;
+            true
+        }
+    }
+    let x = Rc::new(TestPEq(RefCell::new(0)));
+    assert!(x == x);
+    assert!(!(x != x));
+    assert_eq!(*x.0.borrow(), 4);
+}
+
+#[test]
+fn eq() {
+    #[derive(Eq)]
+    struct TestEq(RefCell<usize>);
+    impl PartialEq for TestEq {
+        fn eq(&self, other: &TestEq) -> bool {
+            *self.0.borrow_mut() += 1;
+            *other.0.borrow_mut() += 1;
+            true
+        }
+    }
+    let x = Rc::new(TestEq(RefCell::new(0)));
+    assert!(x == x);
+    assert!(!(x != x));
+    assert_eq!(*x.0.borrow(), 0);
+}
+
+const SHARED_ITER_MAX: u16 = 100;
+
+fn assert_trusted_len<I: TrustedLen>(_: &I) {}
+
+#[test]
+fn shared_from_iter_normal() {
+    // Exercise the base implementation for non-`TrustedLen` iterators.
+    {
+        // `Filter` is never `TrustedLen` since we don't
+        // know statically how many elements will be kept:
+        let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new);
+
+        // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
+        let vec = iter.clone().collect::<Vec<_>>();
+        let rc = iter.collect::<Rc<[_]>>();
+        assert_eq!(&*vec, &*rc);
+
+        // Clone a bit and let these get dropped.
+        {
+            let _rc_2 = rc.clone();
+            let _rc_3 = rc.clone();
+            let _rc_4 = Rc::downgrade(&_rc_3);
+        }
+    } // Drop what hasn't been here.
+}
+
+#[test]
+fn shared_from_iter_trustedlen_normal() {
+    // Exercise the `TrustedLen` implementation under normal circumstances
+    // where `size_hint()` matches `(_, Some(exact_len))`.
+    {
+        let iter = (0..SHARED_ITER_MAX).map(Box::new);
+        assert_trusted_len(&iter);
+
+        // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
+        let vec = iter.clone().collect::<Vec<_>>();
+        let rc = iter.collect::<Rc<[_]>>();
+        assert_eq!(&*vec, &*rc);
+        assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc));
+
+        // Clone a bit and let these get dropped.
+        {
+            let _rc_2 = rc.clone();
+            let _rc_3 = rc.clone();
+            let _rc_4 = Rc::downgrade(&_rc_3);
+        }
+    } // Drop what hasn't been here.
+
+    // Try a ZST to make sure it is handled well.
+    {
+        let iter = (0..SHARED_ITER_MAX).map(drop);
+        let vec = iter.clone().collect::<Vec<_>>();
+        let rc = iter.collect::<Rc<[_]>>();
+        assert_eq!(&*vec, &*rc);
+        assert_eq!(0, size_of_val(&*rc));
+        {
+            let _rc_2 = rc.clone();
+            let _rc_3 = rc.clone();
+            let _rc_4 = Rc::downgrade(&_rc_3);
+        }
+    }
+}
+
+#[test]
+#[should_panic = "I've almost got 99 problems."]
+fn shared_from_iter_trustedlen_panic() {
+    // Exercise the `TrustedLen` implementation when `size_hint()` matches
+    // `(_, Some(exact_len))` but where `.next()` drops before the last iteration.
+    let iter = (0..SHARED_ITER_MAX).map(|val| match val {
+        98 => panic!("I've almost got 99 problems."),
+        _ => Box::new(val),
+    });
+    assert_trusted_len(&iter);
+    let _ = iter.collect::<Rc<[_]>>();
+
+    panic!("I am unreachable.");
+}
+
+#[test]
+fn shared_from_iter_trustedlen_no_fuse() {
+    // Exercise the `TrustedLen` implementation when `size_hint()` matches
+    // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner.
+    struct Iter(std::vec::IntoIter<Option<Box<u8>>>);
+
+    unsafe impl TrustedLen for Iter {}
+
+    impl Iterator for Iter {
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            (2, Some(2))
+        }
+
+        type Item = Box<u8>;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next().flatten()
+        }
+    }
+
+    let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))];
+    let iter = Iter(vec.into_iter());
+    assert_trusted_len(&iter);
+    assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
+}
+
+#[test]
+fn weak_may_dangle() {
+    fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+        val.clone()
+    }
+
+    // Without #[may_dangle] we get:
+    let mut val = Weak::new();
+    hmm(&mut val);
+    //  ~~~~~~~~ borrowed value does not live long enough
+    //
+    // `val` dropped here while still borrowed
+    // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
+}
+
+/// Test that a panic from a destructor does not leak the allocation.
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn panic_no_leak() {
+    use std::alloc::{AllocError, Allocator, Global, Layout};
+    use std::panic::{AssertUnwindSafe, catch_unwind};
+    use std::ptr::NonNull;
+
+    struct AllocCount(Cell<i32>);
+    unsafe impl Allocator for AllocCount {
+        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+            self.0.set(self.0.get() + 1);
+            Global.allocate(layout)
+        }
+        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+            self.0.set(self.0.get() - 1);
+            unsafe { Global.deallocate(ptr, layout) }
+        }
+    }
+
+    struct PanicOnDrop;
+    impl Drop for PanicOnDrop {
+        fn drop(&mut self) {
+            panic!("PanicOnDrop");
+        }
+    }
+
+    let alloc = AllocCount(Cell::new(0));
+    let rc = Rc::new_in(PanicOnDrop, &alloc);
+    assert_eq!(alloc.0.get(), 1);
+
+    let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err();
+    assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
+    assert_eq!(alloc.0.get(), 0);
+}
+
+#[allow(unused)]
+mod pin_coerce_unsized {
+    use alloc::rc::{Rc, UniqueRc};
+    use core::pin::Pin;
+
+    pub trait MyTrait {}
+    impl MyTrait for String {}
+
+    // Pin coercion should work for Rc
+    pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> {
+        arg
+    }
+    pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> {
+        arg
+    }
+}
 
 #[test]
 fn test_clone() {
@@ -61,16 +317,20 @@ fn weak_self_cyclic() {
 
 #[test]
 fn is_unique() {
+    fn is_unique<T>(this: &Rc<T>) -> bool {
+        Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
+    }
+
     let x = Rc::new(3);
-    assert!(Rc::is_unique(&x));
+    assert!(is_unique(&x));
     let y = x.clone();
-    assert!(!Rc::is_unique(&x));
+    assert!(!is_unique(&x));
     drop(y);
-    assert!(Rc::is_unique(&x));
+    assert!(is_unique(&x));
     let w = Rc::downgrade(&x);
-    assert!(!Rc::is_unique(&x));
+    assert!(!is_unique(&x));
     drop(w);
-    assert!(Rc::is_unique(&x));
+    assert!(is_unique(&x));
 }
 
 #[test]
diff --git a/library/alloc/tests/slice.rs b/library/alloctests/tests/slice.rs
index f990a41b679..2516563187f 100644
--- a/library/alloc/tests/slice.rs
+++ b/library/alloctests/tests/slice.rs
@@ -1,7 +1,7 @@
 use std::cmp::Ordering::{Equal, Greater, Less};
 use std::convert::identity;
 use std::rc::Rc;
-use std::{fmt, mem, panic};
+use std::{fmt, panic};
 
 fn square(n: usize) -> usize {
     n * n
@@ -73,7 +73,7 @@ fn test_len_divzero() {
     let v0: &[Z] = &[];
     let v1: &[Z] = &[[]];
     let v2: &[Z] = &[[], []];
-    assert_eq!(mem::size_of::<Z>(), 0);
+    assert_eq!(size_of::<Z>(), 0);
     assert_eq!(v0.len(), 0);
     assert_eq!(v1.len(), 1);
     assert_eq!(v2.len(), 2);
diff --git a/library/alloc/tests/sort/ffi_types.rs b/library/alloctests/tests/sort/ffi_types.rs
index 11515ea4769..11515ea4769 100644
--- a/library/alloc/tests/sort/ffi_types.rs
+++ b/library/alloctests/tests/sort/ffi_types.rs
diff --git a/library/alloc/tests/sort/known_good_stable_sort.rs b/library/alloctests/tests/sort/known_good_stable_sort.rs
index f8615435fc2..2df89146253 100644
--- a/library/alloc/tests/sort/known_good_stable_sort.rs
+++ b/library/alloctests/tests/sort/known_good_stable_sort.rs
@@ -5,7 +5,7 @@
 // Based on https://github.com/voultapher/tiny-sort-rs.
 
 use alloc::alloc::{Layout, alloc, dealloc};
-use std::{mem, ptr};
+use std::ptr;
 
 /// Sort `v` preserving initial order of equal elements.
 ///
@@ -26,7 +26,7 @@ pub fn sort<T: Ord>(v: &mut [T]) {
 
 #[inline(always)]
 fn stable_sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], mut is_less: F) {
-    if mem::size_of::<T>() == 0 {
+    if size_of::<T>() == 0 {
         return;
     }
 
@@ -166,7 +166,7 @@ struct BufGuard<T> {
 impl<T> BufGuard<T> {
     // SAFETY: The caller has to ensure that len is not 0 and that T is not a ZST.
     unsafe fn new(len: usize) -> Self {
-        debug_assert!(len > 0 && mem::size_of::<T>() > 0);
+        debug_assert!(len > 0 && size_of::<T>() > 0);
 
         // SAFETY: See function safety description.
         let layout = unsafe { unwrap_unchecked(Layout::array::<T>(len).ok()) };
diff --git a/library/alloc/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs
index 0e2494ca9d3..0e2494ca9d3 100644
--- a/library/alloc/tests/sort/mod.rs
+++ b/library/alloctests/tests/sort/mod.rs
diff --git a/library/alloc/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs
index 0f1ec664d3d..0f1ec664d3d 100644
--- a/library/alloc/tests/sort/patterns.rs
+++ b/library/alloctests/tests/sort/patterns.rs
diff --git a/library/alloc/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs
index d321f8df518..d321f8df518 100644
--- a/library/alloc/tests/sort/tests.rs
+++ b/library/alloctests/tests/sort/tests.rs
diff --git a/library/alloc/tests/sort/zipf.rs b/library/alloctests/tests/sort/zipf.rs
index 3dad2db521f..3dad2db521f 100644
--- a/library/alloc/tests/sort/zipf.rs
+++ b/library/alloctests/tests/sort/zipf.rs
diff --git a/library/alloc/tests/str.rs b/library/alloctests/tests/str.rs
index 906fa2d425e..906fa2d425e 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloctests/tests/str.rs
diff --git a/library/alloc/tests/string.rs b/library/alloctests/tests/string.rs
index d996c55f946..d996c55f946 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloctests/tests/string.rs
diff --git a/library/alloc/tests/sync.rs b/library/alloctests/tests/sync.rs
index 6d3ab1b1d11..6d3ab1b1d11 100644
--- a/library/alloc/tests/sync.rs
+++ b/library/alloctests/tests/sync.rs
diff --git a/library/alloc/tests/task.rs b/library/alloctests/tests/task.rs
index 390dec14484..390dec14484 100644
--- a/library/alloc/tests/task.rs
+++ b/library/alloctests/tests/task.rs
diff --git a/library/alloc/tests/testing/crash_test.rs b/library/alloctests/tests/testing/crash_test.rs
index 502fe6c10c6..502fe6c10c6 100644
--- a/library/alloc/tests/testing/crash_test.rs
+++ b/library/alloctests/tests/testing/crash_test.rs
diff --git a/library/alloc/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs
index 0a3dd191dc8..0a3dd191dc8 100644
--- a/library/alloc/tests/testing/mod.rs
+++ b/library/alloctests/tests/testing/mod.rs
diff --git a/library/alloc/tests/thin_box.rs b/library/alloctests/tests/thin_box.rs
index e008b0cc357..4c46b614127 100644
--- a/library/alloc/tests/thin_box.rs
+++ b/library/alloctests/tests/thin_box.rs
@@ -1,5 +1,4 @@
 use core::fmt::Debug;
-use core::mem::size_of;
 use std::boxed::ThinBox;
 
 #[test]
@@ -52,7 +51,7 @@ fn verify_aligned<T>(ptr: *const T) {
         ptr.is_aligned() && !ptr.is_null(),
         "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}",
         ty = core::any::type_name::<T>(),
-        align = core::mem::align_of::<T>(),
+        align = align_of::<T>(),
     );
 }
 
diff --git a/library/alloc/tests/vec.rs b/library/alloctests/tests/vec.rs
index fe1db56414e..f430d979fa8 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloctests/tests/vec.rs
@@ -11,14 +11,14 @@ use std::borrow::Cow;
 use std::cell::Cell;
 use std::collections::TryReserveErrorKind::*;
 use std::fmt::Debug;
+use std::hint;
 use std::iter::InPlaceIterable;
-use std::mem::{size_of, swap};
+use std::mem::swap;
 use std::ops::Bound::*;
 use std::panic::{AssertUnwindSafe, catch_unwind};
 use std::rc::Rc;
 use std::sync::atomic::{AtomicU32, Ordering};
 use std::vec::{Drain, IntoIter};
-use std::{hint, mem};
 
 struct DropCounter<'a> {
     count: &'a mut u32,
@@ -1134,7 +1134,7 @@ fn test_into_iter_zst() {
     impl Drop for AlignedZstWithDrop {
         fn drop(&mut self) {
             let addr = self as *mut _ as usize;
-            assert!(hint::black_box(addr) % mem::align_of::<u64>() == 0);
+            assert!(hint::black_box(addr) % align_of::<u64>() == 0);
         }
     }
 
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs
index 1b03c29e5bd..1b03c29e5bd 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloctests/tests/vec_deque.rs
diff --git a/library/alloc/tests/vec_deque_alloc_error.rs b/library/alloctests/tests/vec_deque_alloc_error.rs
index 21a9118a05b..21a9118a05b 100644
--- a/library/alloc/tests/vec_deque_alloc_error.rs
+++ b/library/alloctests/tests/vec_deque_alloc_error.rs
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 17f4d68867e..1595a3af883 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -17,7 +17,7 @@ use crate::{assert_unsafe_precondition, fmt, mem};
 // * https://github.com/rust-lang/rust/pull/72189
 // * https://github.com/rust-lang/rust/pull/79827
 const fn size_align<T>() -> (usize, usize) {
-    (mem::size_of::<T>(), mem::align_of::<T>())
+    (size_of::<T>(), align_of::<T>())
 }
 
 /// Layout of a block of memory.
@@ -182,7 +182,7 @@ impl Layout {
     #[must_use]
     #[inline]
     pub const fn for_value<T: ?Sized>(t: &T) -> Self {
-        let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
+        let (size, align) = (size_of_val(t), align_of_val(t));
         // SAFETY: see rationale in `new` for why this is using the unsafe variant
         unsafe { Layout::from_size_align_unchecked(size, align) }
     }
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 73ab4f1e52a..ac808038f89 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -40,11 +40,9 @@ impl From<char> for u32 {
     /// # Examples
     ///
     /// ```
-    /// use std::mem;
-    ///
     /// let c = 'c';
     /// let u = u32::from(c);
-    /// assert!(4 == mem::size_of_val(&u))
+    /// assert!(4 == size_of_val(&u))
     /// ```
     #[inline]
     fn from(c: char) -> Self {
@@ -59,11 +57,9 @@ impl From<char> for u64 {
     /// # Examples
     ///
     /// ```
-    /// use std::mem;
-    ///
     /// let c = '👤';
     /// let u = u64::from(c);
-    /// assert!(8 == mem::size_of_val(&u))
+    /// assert!(8 == size_of_val(&u))
     /// ```
     #[inline]
     fn from(c: char) -> Self {
@@ -80,11 +76,9 @@ impl From<char> for u128 {
     /// # Examples
     ///
     /// ```
-    /// use std::mem;
-    ///
     /// let c = '⚙';
     /// let u = u128::from(c);
-    /// assert!(16 == mem::size_of_val(&u))
+    /// assert!(16 == size_of_val(&u))
     /// ```
     #[inline]
     fn from(c: char) -> Self {
@@ -167,11 +161,9 @@ impl From<u8> for char {
     /// # Examples
     ///
     /// ```
-    /// use std::mem;
-    ///
     /// let u = 32 as u8;
     /// let c = char::from(u);
-    /// assert!(4 == mem::size_of_val(&c))
+    /// assert!(4 == size_of_val(&c))
     /// ```
     #[inline]
     fn from(i: u8) -> Self {
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 85cc315626d..bb71af339b8 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -337,7 +337,7 @@ impl char {
     /// '1'.is_digit(1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")]
+    #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_digit(self, radix: u32) -> bool {
         self.to_digit(radix).is_some()
@@ -886,7 +886,7 @@ impl char {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")]
+    #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_whitespace(self) -> bool {
         match self {
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 00300328b64..c777dd995a6 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -184,6 +184,59 @@ pub macro Clone($item:item) {
     /* compiler built-in */
 }
 
+/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted)
+///
+/// Cloning an object implementing this trait should in general:
+/// - be O(1) (constant) time regardless of the amount of data managed by the object,
+/// - not require a memory allocation,
+/// - not require copying more than roughly 64 bytes (a typical cache line size),
+/// - not block the current thread,
+/// - not have any semantic side effects (e.g. allocating a file descriptor), and
+/// - not have overhead larger than a couple of atomic operations.
+///
+/// The `UseCloned` trait does not provide a method; instead, it indicates that
+/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax.
+///
+/// ## .use postfix syntax
+///
+/// Values can be `.use`d by adding `.use` postfix to the value you want to use.
+///
+/// ```ignore (this won't work until we land use)
+/// fn foo(f: Foo) {
+///     // if `Foo` implements `Copy` f would be copied into x.
+///     // if `Foo` implements `UseCloned` f would be cloned into x.
+///     // otherwise f would be moved into x.
+///     let x = f.use;
+///     // ...
+/// }
+/// ```
+///
+/// ## use closures
+///
+/// Use closures allow captured values to be automatically used.
+/// This is similar to have a closure that you would call `.use` over each captured value.
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+#[cfg_attr(not(bootstrap), lang = "use_cloned")]
+pub trait UseCloned: Clone {
+    // Empty.
+}
+
+macro_rules! impl_use_cloned {
+    ($($t:ty)*) => {
+        $(
+            #[unstable(feature = "ergonomic_clones", issue = "132290")]
+            impl UseCloned for $t {}
+        )*
+    }
+}
+
+impl_use_cloned! {
+    usize u8 u16 u32 u64 u128
+    isize i8 i16 i32 i64 i128
+             f16 f32 f64 f128
+    bool char
+}
+
 // FIXME(aburka): these structs are used solely by #[derive] to
 // assert that every component of a type implements Clone or Copy.
 //
@@ -244,8 +297,8 @@ pub unsafe trait CloneToUninit {
     ///
     /// Behavior is undefined if any of the following conditions are violated:
     ///
-    /// * `dst` must be [valid] for writes for `std::mem::size_of_val(self)` bytes.
-    /// * `dst` must be properly aligned to `std::mem::align_of_val(self)`.
+    /// * `dst` must be [valid] for writes for `size_of_val(self)` bytes.
+    /// * `dst` must be properly aligned to `align_of_val(self)`.
     ///
     /// [valid]: crate::ptr#safety
     /// [pointer metadata]: crate::ptr::metadata()
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index c8ced78c4d7..b29251b4b43 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -397,6 +397,12 @@ pub enum Ordering {
 }
 
 impl Ordering {
+    #[inline]
+    const fn as_raw(self) -> i8 {
+        // FIXME(const-hack): just use `PartialOrd` against `Equal` once that's const
+        crate::intrinsics::discriminant_value(&self)
+    }
+
     /// Returns `true` if the ordering is the `Equal` variant.
     ///
     /// # Examples
@@ -413,7 +419,11 @@ impl Ordering {
     #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
     #[stable(feature = "ordering_helpers", since = "1.53.0")]
     pub const fn is_eq(self) -> bool {
-        matches!(self, Equal)
+        // All the `is_*` methods are implemented as comparisons against zero
+        // to follow how clang's libcxx implements their equivalents in
+        // <https://github.com/llvm/llvm-project/blob/60486292b79885b7800b082754153202bef5b1f0/libcxx/include/__compare/is_eq.h#L23-L28>
+
+        self.as_raw() == 0
     }
 
     /// Returns `true` if the ordering is not the `Equal` variant.
@@ -432,7 +442,7 @@ impl Ordering {
     #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
     #[stable(feature = "ordering_helpers", since = "1.53.0")]
     pub const fn is_ne(self) -> bool {
-        !matches!(self, Equal)
+        self.as_raw() != 0
     }
 
     /// Returns `true` if the ordering is the `Less` variant.
@@ -451,7 +461,7 @@ impl Ordering {
     #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
     #[stable(feature = "ordering_helpers", since = "1.53.0")]
     pub const fn is_lt(self) -> bool {
-        matches!(self, Less)
+        self.as_raw() < 0
     }
 
     /// Returns `true` if the ordering is the `Greater` variant.
@@ -470,7 +480,7 @@ impl Ordering {
     #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
     #[stable(feature = "ordering_helpers", since = "1.53.0")]
     pub const fn is_gt(self) -> bool {
-        matches!(self, Greater)
+        self.as_raw() > 0
     }
 
     /// Returns `true` if the ordering is either the `Less` or `Equal` variant.
@@ -489,7 +499,7 @@ impl Ordering {
     #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
     #[stable(feature = "ordering_helpers", since = "1.53.0")]
     pub const fn is_le(self) -> bool {
-        !matches!(self, Greater)
+        self.as_raw() <= 0
     }
 
     /// Returns `true` if the ordering is either the `Greater` or `Equal` variant.
@@ -508,7 +518,7 @@ impl Ordering {
     #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
     #[stable(feature = "ordering_helpers", since = "1.53.0")]
     pub const fn is_ge(self) -> bool {
-        !matches!(self, Less)
+        self.as_raw() >= 0
     }
 
     /// Reverses the `Ordering`.
diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs
index ece3c7538da..6495e61b346 100644
--- a/library/core/src/ffi/primitives.rs
+++ b/library/core/src/ffi/primitives.rs
@@ -39,7 +39,6 @@ mod c_char_definition {
         // These are the targets on which c_char is unsigned. Usually the
         // signedness is the same for all target_os values on a given architecture
         // but there are some exceptions (see isSignedCharDefault() in clang).
-        //
         // aarch64:
         //   Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the Arm®
         //   64-bit Architecture (AArch64) says C/C++ char is unsigned byte.
@@ -97,14 +96,19 @@ mod c_char_definition {
         //   are promoted to int as if from type signed char by default, unless the /J compilation
         //   option is used."
         //   https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types
+        // Vita:
+        //   Chars are signed by default on the Vita, and VITASDK follows that convention.
+        //   https://github.com/vitasdk/buildscripts/blob/09c533b771591ecde88864b6acad28ffb688dbd4/patches/gcc/0001-gcc-10.patch#L33-L34
+        //
         // L4Re:
-        //   The kernel builds with -funsigned-char on all targets (but useserspace follows the
+        //   The kernel builds with -funsigned-char on all targets (but userspace follows the
         //   architecture defaults). As we only have a target for userspace apps so there are no
         //   special cases for L4Re below.
         //   https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240
         if #[cfg(all(
             not(windows),
             not(target_vendor = "apple"),
+            not(target_os = "vita"),
             any(
                 target_arch = "aarch64",
                 target_arch = "arm",
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 7a6630c82d0..f7b874b26bb 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -801,7 +801,7 @@ impl<H> Eq for BuildHasherDefault<H> {}
 
 mod impls {
     use super::*;
-    use crate::{mem, slice};
+    use crate::slice;
 
     macro_rules! impl_write {
         ($(($ty:ident, $meth:ident),)*) => {$(
@@ -814,7 +814,7 @@ mod impls {
 
                 #[inline]
                 fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
-                    let newlen = mem::size_of_val(data);
+                    let newlen = size_of_val(data);
                     let ptr = data.as_ptr() as *const u8;
                     // SAFETY: `ptr` is valid and aligned, as this macro is only used
                     // for numeric primitives which have no padding. The new slice only
diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs
index 6ea3241c593..780e522c48e 100644
--- a/library/core/src/hash/sip.rs
+++ b/library/core/src/hash/sip.rs
@@ -3,7 +3,7 @@
 #![allow(deprecated)] // the types in this module are deprecated
 
 use crate::marker::PhantomData;
-use crate::{cmp, mem, ptr};
+use crate::{cmp, ptr};
 
 /// An implementation of SipHash 1-3.
 ///
@@ -99,12 +99,12 @@ macro_rules! compress {
 /// `$i..$i+size_of::<$int_ty>()`, so that must be in-bounds.
 macro_rules! load_int_le {
     ($buf:expr, $i:expr, $int_ty:ident) => {{
-        debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
+        debug_assert!($i + size_of::<$int_ty>() <= $buf.len());
         let mut data = 0 as $int_ty;
         ptr::copy_nonoverlapping(
             $buf.as_ptr().add($i),
             &mut data as *mut _ as *mut u8,
-            mem::size_of::<$int_ty>(),
+            size_of::<$int_ty>(),
         );
         data.to_le()
     }};
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 38a60338e74..6af647b137d 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -10,7 +10,7 @@
 //!
 //! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new"
 //! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the
-//! implementation from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics> to
+//! implementation from <https://github.com/rust-lang/miri/blob/master/src/intrinsics> to
 //! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>
 //! and make the intrinsic declaration a `const fn`.
 //!
@@ -3340,7 +3340,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize;
 /// More specifically, this is the offset in bytes between successive
 /// items of the same type, including alignment padding.
 ///
-/// The stabilized version of this intrinsic is [`core::mem::size_of`].
+/// The stabilized version of this intrinsic is [`size_of`].
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
@@ -3354,7 +3354,7 @@ pub const fn size_of<T>() -> usize;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 ///
-/// The stabilized version of this intrinsic is [`core::mem::align_of`].
+/// The stabilized version of this intrinsic is [`align_of`].
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
@@ -3386,7 +3386,7 @@ pub const fn variant_count<T>() -> usize;
 
 /// The size of the referenced value in bytes.
 ///
-/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`].
+/// The stabilized version of this intrinsic is [`size_of_val`].
 ///
 /// # Safety
 ///
@@ -3399,7 +3399,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(_ptr: *const T) -> usize;
 
 /// The required alignment of the referenced value.
 ///
-/// The stabilized version of this intrinsic is [`core::mem::align_of_val`].
+/// The stabilized version of this intrinsic is [`align_of_val`].
 ///
 /// # Safety
 ///
diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs
index cb13023c85c..a9c07fee2a9 100644
--- a/library/core/src/iter/adapters/map_windows.rs
+++ b/library/core/src/iter/adapters/map_windows.rs
@@ -1,5 +1,5 @@
 use crate::iter::FusedIterator;
-use crate::mem::{self, MaybeUninit};
+use crate::mem::MaybeUninit;
 use crate::{fmt, ptr};
 
 /// An iterator over the mapped windows of another iterator.
@@ -50,7 +50,7 @@ impl<I: Iterator, F, const N: usize> MapWindows<I, F, N> {
         assert!(N != 0, "array in `Iterator::map_windows` must contain more than 0 elements");
 
         // Only ZST arrays' length can be so large.
-        if mem::size_of::<I::Item>() == 0 {
+        if size_of::<I::Item>() == 0 {
             assert!(
                 N.checked_mul(2).is_some(),
                 "array size of `Iterator::map_windows` is too large"
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index e2dd813981d..e234f105b0b 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -405,7 +405,7 @@ marker_impls! {
 ///
 /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
 /// [`String`]: ../../std/string/struct.String.html
-/// [`size_of::<T>`]: crate::mem::size_of
+/// [`size_of::<T>`]: size_of
 /// [impls]: #implementors
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "copy"]
@@ -731,7 +731,6 @@ impl<T: ?Sized> !Sync for *mut T {}
 /// # }
 /// # fn convert_params(_: ParamType) -> usize { 42 }
 /// use std::marker::PhantomData;
-/// use std::mem;
 ///
 /// struct ExternalResource<R> {
 ///    resource_handle: *mut (),
@@ -740,7 +739,7 @@ impl<T: ?Sized> !Sync for *mut T {}
 ///
 /// impl<R: ResType> ExternalResource<R> {
 ///     fn new() -> Self {
-///         let size_of_res = mem::size_of::<R>();
+///         let size_of_res = size_of::<R>();
 ///         Self {
 ///             resource_handle: foreign_lib::new(size_of_res),
 ///             resource_type: PhantomData,
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 067371c1b58..ce84f105e5c 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -203,7 +203,7 @@ use crate::{fmt, intrinsics, ptr, slice};
 /// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as `T`:
 ///
 /// ```rust
-/// use std::mem::{MaybeUninit, size_of, align_of};
+/// use std::mem::MaybeUninit;
 /// assert_eq!(size_of::<MaybeUninit<u64>>(), size_of::<u64>());
 /// assert_eq!(align_of::<MaybeUninit<u64>>(), align_of::<u64>());
 /// ```
@@ -215,7 +215,7 @@ use crate::{fmt, intrinsics, ptr, slice};
 /// optimizations, potentially resulting in a larger size:
 ///
 /// ```rust
-/// # use std::mem::{MaybeUninit, size_of};
+/// # use std::mem::MaybeUninit;
 /// assert_eq!(size_of::<Option<bool>>(), 1);
 /// assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);
 /// ```
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index b9bb6d6a13f..caab7a6ddb5 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -226,31 +226,27 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 /// # Examples
 ///
 /// ```
-/// use std::mem;
-///
 /// // Some primitives
-/// assert_eq!(4, mem::size_of::<i32>());
-/// assert_eq!(8, mem::size_of::<f64>());
-/// assert_eq!(0, mem::size_of::<()>());
+/// assert_eq!(4, size_of::<i32>());
+/// assert_eq!(8, size_of::<f64>());
+/// assert_eq!(0, size_of::<()>());
 ///
 /// // Some arrays
-/// assert_eq!(8, mem::size_of::<[i32; 2]>());
-/// assert_eq!(12, mem::size_of::<[i32; 3]>());
-/// assert_eq!(0, mem::size_of::<[i32; 0]>());
+/// assert_eq!(8, size_of::<[i32; 2]>());
+/// assert_eq!(12, size_of::<[i32; 3]>());
+/// assert_eq!(0, size_of::<[i32; 0]>());
 ///
 ///
 /// // Pointer size equality
-/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>());
-/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Box<i32>>());
-/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Option<&i32>>());
-/// assert_eq!(mem::size_of::<Box<i32>>(), mem::size_of::<Option<Box<i32>>>());
+/// assert_eq!(size_of::<&i32>(), size_of::<*const i32>());
+/// assert_eq!(size_of::<&i32>(), size_of::<Box<i32>>());
+/// assert_eq!(size_of::<&i32>(), size_of::<Option<&i32>>());
+/// assert_eq!(size_of::<Box<i32>>(), size_of::<Option<Box<i32>>>());
 /// ```
 ///
 /// Using `#[repr(C)]`.
 ///
 /// ```
-/// use std::mem;
-///
 /// #[repr(C)]
 /// struct FieldStruct {
 ///     first: u8,
@@ -265,13 +261,13 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 /// // The size of the third field is 1, so add 1 to the size. Size is 5.
 /// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its
 /// // fields is 2), so add 1 to the size for padding. Size is 6.
-/// assert_eq!(6, mem::size_of::<FieldStruct>());
+/// assert_eq!(6, size_of::<FieldStruct>());
 ///
 /// #[repr(C)]
 /// struct TupleStruct(u8, u16, u8);
 ///
 /// // Tuple structs follow the same rules.
-/// assert_eq!(6, mem::size_of::<TupleStruct>());
+/// assert_eq!(6, size_of::<TupleStruct>());
 ///
 /// // Note that reordering the fields can lower the size. We can remove both padding bytes
 /// // by putting `third` before `second`.
@@ -282,7 +278,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 ///     second: u16
 /// }
 ///
-/// assert_eq!(4, mem::size_of::<FieldStructOptimized>());
+/// assert_eq!(4, size_of::<FieldStructOptimized>());
 ///
 /// // Union size is the size of the largest field.
 /// #[repr(C)]
@@ -291,7 +287,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 ///     larger: u16
 /// }
 ///
-/// assert_eq!(2, mem::size_of::<ExampleUnion>());
+/// assert_eq!(2, size_of::<ExampleUnion>());
 /// ```
 ///
 /// [alignment]: align_of
@@ -320,13 +316,11 @@ pub const fn size_of<T>() -> usize {
 /// # Examples
 ///
 /// ```
-/// use std::mem;
-///
-/// assert_eq!(4, mem::size_of_val(&5i32));
+/// assert_eq!(4, size_of_val(&5i32));
 ///
 /// let x: [u8; 13] = [0; 13];
 /// let y: &[u8] = &x;
-/// assert_eq!(13, mem::size_of_val(y));
+/// assert_eq!(13, size_of_val(y));
 /// ```
 ///
 /// [`size_of::<T>()`]: size_of
@@ -381,7 +375,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 /// #![feature(layout_for_ptr)]
 /// use std::mem;
 ///
-/// assert_eq!(4, mem::size_of_val(&5i32));
+/// assert_eq!(4, size_of_val(&5i32));
 ///
 /// let x: [u8; 13] = [0; 13];
 /// let y: &[u8] = &x;
@@ -454,9 +448,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 /// # Examples
 ///
 /// ```
-/// use std::mem;
-///
-/// assert_eq!(4, mem::align_of::<i32>());
+/// assert_eq!(4, align_of::<i32>());
 /// ```
 #[inline(always)]
 #[must_use]
@@ -477,9 +469,7 @@ pub const fn align_of<T>() -> usize {
 /// # Examples
 ///
 /// ```
-/// use std::mem;
-///
-/// assert_eq!(4, mem::align_of_val(&5i32));
+/// assert_eq!(4, align_of_val(&5i32));
 /// ```
 #[inline]
 #[must_use]
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index 7b920d7a777..782b826448a 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -153,7 +153,7 @@ pub struct Assume {
     ///
     /// ```compile_fail,E0277
     /// #![feature(transmutability)]
-    /// use core::mem::{align_of, TransmuteFrom};
+    /// use core::mem::TransmuteFrom;
     ///
     /// assert_eq!(align_of::<[u8; 2]>(), 1);
     /// assert_eq!(align_of::<u16>(), 2);
@@ -172,7 +172,7 @@ pub struct Assume {
     ///
     /// ```rust
     /// #![feature(pointer_is_aligned_to, transmutability)]
-    /// use core::mem::{align_of, Assume, TransmuteFrom};
+    /// use core::mem::{Assume, TransmuteFrom};
     ///
     /// let src: &[u8; 2] = &[0xFF, 0xFF];
     ///
@@ -337,7 +337,7 @@ impl Assume {
     ///     transmutability,
     /// )]
     /// #![allow(incomplete_features)]
-    /// use core::mem::{align_of, Assume, TransmuteFrom};
+    /// use core::mem::{Assume, TransmuteFrom};
     ///
     /// /// Attempts to transmute `src` to `&Dst`.
     /// ///
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 9204797e6e1..57f47e66e81 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -200,7 +200,7 @@ impl SocketAddr {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_ip(&mut self, new_ip: IpAddr) {
         // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
         match (self, new_ip) {
@@ -244,7 +244,7 @@ impl SocketAddr {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_port(&mut self, new_port: u16) {
         match *self {
             SocketAddr::V4(ref mut a) => a.set_port(new_port),
@@ -350,7 +350,7 @@ impl SocketAddrV4 {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_ip(&mut self, new_ip: Ipv4Addr) {
         self.ip = new_ip;
     }
@@ -386,7 +386,7 @@ impl SocketAddrV4 {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
@@ -448,7 +448,7 @@ impl SocketAddrV6 {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_ip(&mut self, new_ip: Ipv6Addr) {
         self.ip = new_ip;
     }
@@ -484,7 +484,7 @@ impl SocketAddrV6 {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
@@ -532,7 +532,7 @@ impl SocketAddrV6 {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_flowinfo(&mut self, new_flowinfo: u32) {
         self.flowinfo = new_flowinfo;
     }
@@ -575,7 +575,7 @@ impl SocketAddrV6 {
     /// ```
     #[inline]
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_scope_id(&mut self, new_scope_id: u32) {
         self.scope_id = new_scope_id;
     }
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index 2a47c89e2ae..e33f58197bb 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -253,12 +253,11 @@ macro_rules! define_bignum {
 
             /// Multiplies itself by `5^e` and returns its own mutable reference.
             pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
-                use crate::mem;
                 use crate::num::bignum::SMALL_POW5;
 
                 // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes
                 // are consecutive powers of two, so this is well suited index for the table.
-                let table_index = mem::size_of::<$ty>().trailing_zeros() as usize;
+                let table_index = size_of::<$ty>().trailing_zeros() as usize;
                 let (small_power, small_e) = SMALL_POW5[table_index];
                 let small_power = small_power as $ty;
 
@@ -405,6 +404,8 @@ macro_rules! define_bignum {
             }
         }
 
+        impl crate::clone::UseCloned for $name {}
+
         impl crate::fmt::Debug for $name {
             fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
                 let sz = if self.size < 1 { 1 } else { self.size };
diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs
index daeee1755b0..8aad087ec1b 100644
--- a/library/core/src/num/dec2flt/fpu.rs
+++ b/library/core/src/num/dec2flt/fpu.rs
@@ -22,7 +22,6 @@ pub(super) use fpu_precision::set_precision;
 #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
 mod fpu_precision {
     use core::arch::asm;
-    use core::mem::size_of;
 
     /// A structure used to preserve the original value of the FPU control word, so that it can be
     /// restored when the structure is dropped.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 7d99aaa1731..a72ca4bcb05 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -3627,7 +3627,7 @@ macro_rules! int_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        pub const fn to_be_bytes(self) -> [u8; size_of::<Self>()] {
             self.to_be().to_ne_bytes()
         }
 
@@ -3647,7 +3647,7 @@ macro_rules! int_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        pub const fn to_le_bytes(self) -> [u8; size_of::<Self>()] {
             self.to_le().to_ne_bytes()
         }
 
@@ -3683,7 +3683,7 @@ macro_rules! int_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        pub const fn to_ne_bytes(self) -> [u8; size_of::<Self>()] {
             // SAFETY: integers are plain old datatypes so we can always transmute them to
             // arrays of bytes
             unsafe { mem::transmute(self) }
@@ -3705,7 +3705,7 @@ macro_rules! int_impl {
         ///
         /// ```
         #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
-        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
         #[doc = concat!("    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")]
         /// }
@@ -3714,7 +3714,7 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
         #[must_use]
         #[inline]
-        pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+        pub const fn from_be_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
             Self::from_be(Self::from_ne_bytes(bytes))
         }
 
@@ -3734,7 +3734,7 @@ macro_rules! int_impl {
         ///
         /// ```
         #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
-        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
         #[doc = concat!("    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")]
         /// }
@@ -3743,7 +3743,7 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
         #[must_use]
         #[inline]
-        pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+        pub const fn from_le_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
             Self::from_le(Self::from_ne_bytes(bytes))
         }
 
@@ -3774,7 +3774,7 @@ macro_rules! int_impl {
         ///
         /// ```
         #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
-        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
         #[doc = concat!("    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")]
         /// }
@@ -3785,7 +3785,7 @@ macro_rules! int_impl {
         // SAFETY: const sound because integers are plain old datatypes so we can always
         // transmute to them
         #[inline]
-        pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+        pub const fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
             // SAFETY: integers are plain old datatypes so we can always transmute to them
             unsafe { mem::transmute(bytes) }
         }
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 80a38a6013d..151e128cd78 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -1241,7 +1241,7 @@ impl usize {
     /// Returns an `usize` where every byte is equal to `x`.
     #[inline]
     pub(crate) const fn repeat_u8(x: u8) -> usize {
-        usize::from_ne_bytes([x; mem::size_of::<usize>()])
+        usize::from_ne_bytes([x; size_of::<usize>()])
     }
 
     /// Returns an `usize` where every byte pair is equal to `x`.
@@ -1249,7 +1249,7 @@ impl usize {
     pub(crate) const fn repeat_u16(x: u16) -> usize {
         let mut r = 0usize;
         let mut i = 0;
-        while i < mem::size_of::<usize>() {
+        while i < size_of::<usize>() {
             // Use `wrapping_shl` to make it work on targets with 16-bit `usize`
             r = r.wrapping_shl(16) | (x as usize);
             i += 2;
@@ -1330,7 +1330,7 @@ pub enum FpCategory {
 #[inline(always)]
 #[unstable(issue = "none", feature = "std_internals")]
 pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
-    radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
+    radix <= 16 && digits.len() <= size_of::<T>() * 2 - is_signed_ty as usize
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index a967b72c4fa..7585ec140e3 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1,6 +1,7 @@
 //! Definitions of integer that is known not to equal zero.
 
 use super::{IntErrorKind, ParseIntError};
+use crate::clone::UseCloned;
 use crate::cmp::Ordering;
 use crate::hash::{Hash, Hasher};
 use crate::marker::{Freeze, StructuralPartialEq};
@@ -86,7 +87,7 @@ impl_zeroable_primitive!(
 /// For example, `Option<NonZero<u32>>` is the same size as `u32`:
 ///
 /// ```
-/// use core::{mem::size_of, num::NonZero};
+/// use core::{num::NonZero};
 ///
 /// assert_eq!(size_of::<Option<NonZero<u32>>>(), size_of::<u32>());
 /// ```
@@ -102,7 +103,6 @@ impl_zeroable_primitive!(
 /// `Option<NonZero<T>>` are guaranteed to have the same size and alignment:
 ///
 /// ```
-/// # use std::mem::{size_of, align_of};
 /// use std::num::NonZero;
 ///
 /// assert_eq!(size_of::<NonZero<u32>>(), size_of::<Option<NonZero<u32>>>());
@@ -183,6 +183,9 @@ where
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
+
 #[stable(feature = "nonzero", since = "1.28.0")]
 impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
 
@@ -500,7 +503,6 @@ macro_rules! nonzero_integer {
         #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")]
         ///
         /// ```rust
-        /// use std::mem::size_of;
         #[doc = concat!("assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int), ">());")]
         /// ```
         ///
@@ -516,7 +518,6 @@ macro_rules! nonzero_integer {
         /// are guaranteed to have the same size and alignment:
         ///
         /// ```
-        /// # use std::mem::{size_of, align_of};
         #[doc = concat!("use std::num::", stringify!($Ty), ";")]
         ///
         #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::<Option<", stringify!($Ty), ">>());")]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 405c71121ca..58689275839 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2533,15 +2533,20 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")]
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
         pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
             // note: longer-term this should be done via an intrinsic, but this has been shown
             //   to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
-            let (a, b) = self.overflowing_sub(rhs);
-            let (c, d) = a.overflowing_sub(borrow as $SelfT);
-            (c, b | d)
+            let (a, c1) = self.overflowing_sub(rhs);
+            let (b, c2) = a.overflowing_sub(borrow as $SelfT);
+            // SAFETY: Only one of `c1` and `c2` can be set.
+            // For c1 to be set we need to have underflowed, but if we did then
+            // `a` is nonzero, which means that `c2` cannot possibly
+            // underflow because it's subtracting at most `1` (since it came from `bool`)
+            (b, unsafe { intrinsics::disjoint_bitor(c1, c2) })
         }
 
         /// Calculates `self` - `rhs` with a signed `rhs`
@@ -2586,7 +2591,7 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         pub const fn abs_diff(self, other: Self) -> Self {
-            if mem::size_of::<Self>() == 1 {
+            if size_of::<Self>() == 1 {
                 // Trick LLVM into generating the psadbw instruction when SSE2
                 // is available and this function is autovectorized for u8's.
                 (self as i32).wrapping_sub(other as i32).abs() as Self
@@ -3465,7 +3470,7 @@ macro_rules! uint_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        pub const fn to_be_bytes(self) -> [u8; size_of::<Self>()] {
             self.to_be().to_ne_bytes()
         }
 
@@ -3485,7 +3490,7 @@ macro_rules! uint_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        pub const fn to_le_bytes(self) -> [u8; size_of::<Self>()] {
             self.to_le().to_ne_bytes()
         }
 
@@ -3521,7 +3526,7 @@ macro_rules! uint_impl {
         // SAFETY: const sound because integers are plain old datatypes so we can always
         // transmute them to arrays of bytes
         #[inline]
-        pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        pub const fn to_ne_bytes(self) -> [u8; size_of::<Self>()] {
             // SAFETY: integers are plain old datatypes so we can always transmute them to
             // arrays of bytes
             unsafe { mem::transmute(self) }
@@ -3543,7 +3548,7 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
-        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
         #[doc = concat!("    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")]
         /// }
@@ -3552,7 +3557,7 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
         #[must_use]
         #[inline]
-        pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+        pub const fn from_be_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
             Self::from_be(Self::from_ne_bytes(bytes))
         }
 
@@ -3572,7 +3577,7 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
-        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
         #[doc = concat!("    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")]
         /// }
@@ -3581,7 +3586,7 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
         #[must_use]
         #[inline]
-        pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+        pub const fn from_le_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
             Self::from_le(Self::from_ne_bytes(bytes))
         }
 
@@ -3612,7 +3617,7 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
-        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
         #[doc = concat!("    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")]
         /// }
@@ -3623,7 +3628,7 @@ macro_rules! uint_impl {
         // SAFETY: const sound because integers are plain old datatypes so we can always
         // transmute to them
         #[inline]
-        pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+        pub const fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
             // SAFETY: integers are plain old datatypes so we can always transmute to them
             unsafe { mem::transmute(bytes) }
         }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index a9f06b92ad5..f668c6f0672 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2050,6 +2050,9 @@ where
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T> crate::clone::UseCloned for Option<T> where T: crate::clone::UseCloned {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Default for Option<T> {
     /// Returns [`None`][Option::None].
diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs
index 590ffd64b5b..8d867a269a2 100644
--- a/library/core/src/prelude/mod.rs
+++ b/library/core/src/prelude/mod.rs
@@ -70,3 +70,26 @@ pub mod rust_2024 {
     #[doc(no_inline)]
     pub use crate::future::{Future, IntoFuture};
 }
+
+/// The Future version of the core prelude.
+///
+/// See the [module-level documentation](self) for more.
+#[doc(hidden)]
+#[unstable(feature = "prelude_future", issue = "none")]
+pub mod rust_future {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[doc(no_inline)]
+    pub use super::v1::*;
+
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
+    #[doc(no_inline)]
+    pub use crate::iter::FromIterator;
+
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
+    #[doc(no_inline)]
+    pub use crate::convert::{TryFrom, TryInto};
+
+    #[stable(feature = "prelude_2024", since = "1.85.0")]
+    #[doc(no_inline)]
+    pub use crate::future::{Future, IntoFuture};
+}
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index bbf5939fe1b..89c856fe107 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -398,12 +398,12 @@ mod prim_never {}
 /// let v = vec!['h', 'e', 'l', 'l', 'o'];
 ///
 /// // five elements times four bytes for each element
-/// assert_eq!(20, v.len() * std::mem::size_of::<char>());
+/// assert_eq!(20, v.len() * size_of::<char>());
 ///
 /// let s = String::from("hello");
 ///
 /// // five elements times one byte per element
-/// assert_eq!(5, s.len() * std::mem::size_of::<u8>());
+/// assert_eq!(5, s.len() * size_of::<u8>());
 /// ```
 ///
 /// [`String`]: ../std/string/struct.String.html
@@ -443,8 +443,8 @@ mod prim_never {}
 /// let s = String::from("love: ❤️");
 /// let v: Vec<char> = s.chars().collect();
 ///
-/// assert_eq!(12, std::mem::size_of_val(&s[..]));
-/// assert_eq!(32, std::mem::size_of_val(&v[..]));
+/// assert_eq!(12, size_of_val(&s[..]));
+/// assert_eq!(32, size_of_val(&v[..]));
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_char {}
@@ -594,10 +594,8 @@ impl () {}
 /// #[allow(unused_extern_crates)]
 /// extern crate libc;
 ///
-/// use std::mem;
-///
 /// unsafe {
-///     let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
+///     let my_num: *mut i32 = libc::malloc(size_of::<i32>()) as *mut i32;
 ///     if my_num.is_null() {
 ///         panic!("failed to allocate memory");
 ///     }
@@ -893,11 +891,11 @@ mod prim_array {}
 ///
 /// ```
 /// # use std::rc::Rc;
-/// let pointer_size = std::mem::size_of::<&u8>();
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
+/// let pointer_size = size_of::<&u8>();
+/// assert_eq!(2 * pointer_size, size_of::<&[u8]>());
+/// assert_eq!(2 * pointer_size, size_of::<*const [u8]>());
+/// assert_eq!(2 * pointer_size, size_of::<Box<[u8]>>());
+/// assert_eq!(2 * pointer_size, size_of::<Rc<[u8]>>());
 /// ```
 ///
 /// ## Trait Implementations
@@ -1692,15 +1690,13 @@ mod prim_ref {}
 /// This zero-sized type *coerces* to a regular function pointer. For example:
 ///
 /// ```rust
-/// use std::mem;
-///
 /// fn bar(x: i32) {}
 ///
 /// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar`
-/// assert_eq!(mem::size_of_val(&not_bar_ptr), 0);
+/// assert_eq!(size_of_val(&not_bar_ptr), 0);
 ///
 /// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer
-/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::<usize>());
+/// assert_eq!(size_of_val(&bar_ptr), size_of::<usize>());
 ///
 /// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar`
 /// ```
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index 2da94e72566..19311e39b45 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -13,8 +13,8 @@ use crate::{cmp, fmt, hash, mem, num};
 pub struct Alignment(AlignmentEnum);
 
 // Alignment is `repr(usize)`, but via extra steps.
-const _: () = assert!(mem::size_of::<Alignment>() == mem::size_of::<usize>());
-const _: () = assert!(mem::align_of::<Alignment>() == mem::align_of::<usize>());
+const _: () = assert!(size_of::<Alignment>() == size_of::<usize>());
+const _: () = assert!(align_of::<Alignment>() == align_of::<usize>());
 
 fn _alignment_can_be_structurally_matched(a: Alignment) -> bool {
     matches!(a, Alignment::MIN)
@@ -38,14 +38,14 @@ impl Alignment {
 
     /// Returns the alignment for a type.
     ///
-    /// This provides the same numerical value as [`mem::align_of`],
+    /// This provides the same numerical value as [`align_of`],
     /// but in an `Alignment` instead of a `usize`.
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
     #[inline]
     #[must_use]
     pub const fn of<T>() -> Self {
         // This can't actually panic since type alignment is always a power of two.
-        const { Alignment::new(mem::align_of::<T>()).unwrap() }
+        const { Alignment::new(align_of::<T>()).unwrap() }
     }
 
     /// Creates an `Alignment` from a `usize`, or returns `None` if it's
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 8db620596dd..9a4f916803e 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1,7 +1,7 @@
 use super::*;
 use crate::cmp::Ordering::{Equal, Greater, Less};
 use crate::intrinsics::const_eval_select;
-use crate::mem::SizedTypeProperties;
+use crate::mem::{self, SizedTypeProperties};
 use crate::slice::{self, SliceIndex};
 
 impl<T: ?Sized> *const T {
@@ -595,9 +595,9 @@ impl<T: ?Sized> *const T {
     }
 
     /// Calculates the distance between two pointers within the same allocation. The returned value is in
-    /// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
+    /// units of T: the distance in bytes divided by `size_of::<T>()`.
     ///
-    /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`,
+    /// This is equivalent to `(self as isize - origin as isize) / (size_of::<T>() as isize)`,
     /// except that it has a lot more opportunities for UB, in exchange for the compiler
     /// better understanding what you are doing.
     ///
@@ -633,7 +633,7 @@ impl<T: ?Sized> *const T {
     /// objects is not known at compile-time. However, the requirement also exists at
     /// runtime and may be exploited by optimizations. If you wish to compute the difference between
     /// pointers that are not guaranteed to be from the same allocation, use `(self as isize -
-    /// origin as isize) / mem::size_of::<T>()`.
+    /// origin as isize) / size_of::<T>()`.
     // FIXME: recommend `addr()` instead of `as usize` once that is stable.
     ///
     /// [`add`]: #method.add
@@ -683,7 +683,7 @@ impl<T: ?Sized> *const T {
     where
         T: Sized,
     {
-        let pointee_size = mem::size_of::<T>();
+        let pointee_size = size_of::<T>();
         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
         // SAFETY: the caller must uphold the safety contract for `ptr_offset_from`.
         unsafe { intrinsics::ptr_offset_from(self, origin) }
@@ -709,7 +709,7 @@ impl<T: ?Sized> *const T {
 
     /// Calculates the distance between two pointers within the same allocation, *where it's known that
     /// `self` is equal to or greater than `origin`*. The returned value is in
-    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
+    /// units of T: the distance in bytes is divided by `size_of::<T>()`.
     ///
     /// This computes the same value that [`offset_from`](#method.offset_from)
     /// would compute, but with the added precondition that the offset is
@@ -793,7 +793,7 @@ impl<T: ?Sized> *const T {
             ) => runtime_ptr_ge(this, origin)
         );
 
-        let pointee_size = mem::size_of::<T>();
+        let pointee_size = size_of::<T>();
         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
         // SAFETY: the caller must uphold the safety contract for `ptr_offset_from_unsigned`.
         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
@@ -1313,7 +1313,7 @@ impl<T: ?Sized> *const T {
         unsafe { read_unaligned(self) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+    /// Copies `count * size_of::<T>()` bytes from `self` to `dest`. The source
     /// and destination may overlap.
     ///
     /// NOTE: this has the *same* argument order as [`ptr::copy`].
@@ -1333,7 +1333,7 @@ impl<T: ?Sized> *const T {
         unsafe { copy(self, dest, count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+    /// Copies `count * size_of::<T>()` bytes from `self` to `dest`. The source
     /// and destination may *not* overlap.
     ///
     /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`].
@@ -1375,8 +1375,6 @@ impl<T: ?Sized> *const T {
     /// Accessing adjacent `u8` as `u16`
     ///
     /// ```
-    /// use std::mem::align_of;
-    ///
     /// # unsafe {
     /// let x = [5_u8, 6, 7, 8, 9];
     /// let ptr = x.as_ptr();
@@ -1436,7 +1434,7 @@ impl<T: ?Sized> *const T {
     where
         T: Sized,
     {
-        self.is_aligned_to(mem::align_of::<T>())
+        self.is_aligned_to(align_of::<T>())
     }
 
     /// Returns whether the pointer is aligned to `align`.
@@ -1595,7 +1593,7 @@ impl<T> *const [T] {
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
-    /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
+    /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
     ///   and it must be properly aligned. This means in particular:
     ///
     ///     * The entire memory range of this slice must be contained within a single [allocated object]!
@@ -1607,7 +1605,7 @@ impl<T> *const [T] {
     ///       them from other data. You can obtain a pointer that is usable as `data`
     ///       for zero-length slices using [`NonNull::dangling()`].
     ///
-    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
     ///   See the safety documentation of [`pointer::offset`].
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 9eee29d485f..48707506389 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -74,7 +74,7 @@ pub trait Pointee {
 /// #![feature(ptr_metadata)]
 ///
 /// fn this_never_panics<T: std::ptr::Thin>() {
-///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
+///     assert_eq!(size_of::<&T>(), size_of::<usize>())
 /// }
 /// ```
 #[unstable(feature = "ptr_metadata", issue = "81513")]
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index eb99be817a2..ea53da78d3b 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -48,7 +48,7 @@
 //!
 //! Valid raw pointers as defined above are not necessarily properly aligned (where
 //! "proper" alignment is defined by the pointee type, i.e., `*const T` must be
-//! aligned to `mem::align_of::<T>()`). However, most functions require their
+//! aligned to `align_of::<T>()`). However, most functions require their
 //! arguments to be properly aligned, and will explicitly state
 //! this requirement in their documentation. Notable exceptions to this are
 //! [`read_unaligned`] and [`write_unaligned`].
@@ -297,7 +297,7 @@
 //!
 //!     // Our value, which must have enough alignment to have spare least-significant-bits.
 //!     let my_precious_data: u32 = 17;
-//!     assert!(core::mem::align_of::<u32>() > 1);
+//!     assert!(align_of::<u32>() > 1);
 //!
 //!     // Create a tagged pointer
 //!     let ptr = &my_precious_data as *const u32;
@@ -1098,12 +1098,12 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
         } else {
             macro_rules! attempt_swap_as_chunks {
                 ($ChunkTy:ty) => {
-                    if mem::align_of::<T>() >= mem::align_of::<$ChunkTy>()
-                        && mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0
+                    if align_of::<T>() >= align_of::<$ChunkTy>()
+                        && size_of::<T>() % size_of::<$ChunkTy>() == 0
                     {
                         let x: *mut $ChunkTy = x.cast();
                         let y: *mut $ChunkTy = y.cast();
-                        let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>());
+                        let count = count * (size_of::<T>() / size_of::<$ChunkTy>());
                         // SAFETY: these are the same bytes that the caller promised were
                         // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s.
                         // The `if` condition above ensures that we're not violating
@@ -1117,9 +1117,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             // Split up the slice into small power-of-two-sized chunks that LLVM is able
             // to vectorize (unless it's a special type with more-than-pointer alignment,
             // because we don't want to pessimize things like slices of SIMD vectors.)
-            if mem::align_of::<T>() <= mem::size_of::<usize>()
-            && (!mem::size_of::<T>().is_power_of_two()
-                || mem::size_of::<T>() > mem::size_of::<usize>() * 2)
+            if align_of::<T>() <= size_of::<usize>()
+            && (!size_of::<T>().is_power_of_two()
+                || size_of::<T>() > size_of::<usize>() * 2)
             {
                 attempt_swap_as_chunks!(usize);
                 attempt_swap_as_chunks!(u8);
@@ -1443,10 +1443,8 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 /// Read a `usize` value from a byte buffer:
 ///
 /// ```
-/// use std::mem;
-///
 /// fn read_usize(x: &[u8]) -> usize {
-///     assert!(x.len() >= mem::size_of::<usize>());
+///     assert!(x.len() >= size_of::<usize>());
 ///
 ///     let ptr = x.as_ptr() as *const usize;
 ///
@@ -1467,7 +1465,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
     // Also, since we just wrote a valid value into `tmp`, it is guaranteed
     // to be properly initialized.
     unsafe {
-        copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::<T>());
+        copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, size_of::<T>());
         tmp.assume_init()
     }
 }
@@ -1647,10 +1645,8 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
 /// Write a `usize` value to a byte buffer:
 ///
 /// ```
-/// use std::mem;
-///
 /// fn write_usize(x: &mut [u8], val: usize) {
-///     assert!(x.len() >= mem::size_of::<usize>());
+///     assert!(x.len() >= size_of::<usize>());
 ///
 ///     let ptr = x.as_mut_ptr() as *mut usize;
 ///
@@ -1667,7 +1663,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
     // `dst` cannot overlap `src` because the caller has mutable access
     // to `dst` while `src` is owned by this function.
     unsafe {
-        copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, mem::size_of::<T>());
+        copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, size_of::<T>());
         // We are calling the intrinsic directly to avoid function calls in the generated code.
         intrinsics::forget(src);
     }
@@ -1911,7 +1907,7 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
         inverse & m_minus_one
     }
 
-    let stride = mem::size_of::<T>();
+    let stride = size_of::<T>();
 
     let addr: usize = p.addr();
 
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 5a64f12ca99..b960a3d86be 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1,7 +1,7 @@
 use super::*;
 use crate::cmp::Ordering::{Equal, Greater, Less};
 use crate::intrinsics::const_eval_select;
-use crate::mem::SizedTypeProperties;
+use crate::mem::{self, SizedTypeProperties};
 use crate::slice::{self, SliceIndex};
 
 impl<T: ?Sized> *mut T {
@@ -769,9 +769,9 @@ impl<T: ?Sized> *mut T {
     }
 
     /// Calculates the distance between two pointers within the same allocation. The returned value is in
-    /// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
+    /// units of T: the distance in bytes divided by `size_of::<T>()`.
     ///
-    /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`,
+    /// This is equivalent to `(self as isize - origin as isize) / (size_of::<T>() as isize)`,
     /// except that it has a lot more opportunities for UB, in exchange for the compiler
     /// better understanding what you are doing.
     ///
@@ -807,7 +807,7 @@ impl<T: ?Sized> *mut T {
     /// objects is not known at compile-time. However, the requirement also exists at
     /// runtime and may be exploited by optimizations. If you wish to compute the difference between
     /// pointers that are not guaranteed to be from the same allocation, use `(self as isize -
-    /// origin as isize) / mem::size_of::<T>()`.
+    /// origin as isize) / size_of::<T>()`.
     // FIXME: recommend `addr()` instead of `as usize` once that is stable.
     ///
     /// [`add`]: #method.add
@@ -881,7 +881,7 @@ impl<T: ?Sized> *mut T {
 
     /// Calculates the distance between two pointers within the same allocation, *where it's known that
     /// `self` is equal to or greater than `origin`*. The returned value is in
-    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
+    /// units of T: the distance in bytes is divided by `size_of::<T>()`.
     ///
     /// This computes the same value that [`offset_from`](#method.offset_from)
     /// would compute, but with the added precondition that the offset is
@@ -1397,7 +1397,7 @@ impl<T: ?Sized> *mut T {
         unsafe { read_unaligned(self) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+    /// Copies `count * size_of::<T>()` bytes from `self` to `dest`. The source
     /// and destination may overlap.
     ///
     /// NOTE: this has the *same* argument order as [`ptr::copy`].
@@ -1417,7 +1417,7 @@ impl<T: ?Sized> *mut T {
         unsafe { copy(self, dest, count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+    /// Copies `count * size_of::<T>()` bytes from `self` to `dest`. The source
     /// and destination may *not* overlap.
     ///
     /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`].
@@ -1437,7 +1437,7 @@ impl<T: ?Sized> *mut T {
         unsafe { copy_nonoverlapping(self, dest, count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `src` to `self`. The source
+    /// Copies `count * size_of::<T>()` bytes from `src` to `self`. The source
     /// and destination may overlap.
     ///
     /// NOTE: this has the *opposite* argument order of [`ptr::copy`].
@@ -1457,7 +1457,7 @@ impl<T: ?Sized> *mut T {
         unsafe { copy(src, self, count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `src` to `self`. The source
+    /// Copies `count * size_of::<T>()` bytes from `src` to `self`. The source
     /// and destination may *not* overlap.
     ///
     /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`].
@@ -1623,8 +1623,6 @@ impl<T: ?Sized> *mut T {
     /// Accessing adjacent `u8` as `u16`
     ///
     /// ```
-    /// use std::mem::align_of;
-    ///
     /// # unsafe {
     /// let mut x = [5_u8, 6, 7, 8, 9];
     /// let ptr = x.as_mut_ptr();
@@ -1689,7 +1687,7 @@ impl<T: ?Sized> *mut T {
     where
         T: Sized,
     {
-        self.is_aligned_to(mem::align_of::<T>())
+        self.is_aligned_to(align_of::<T>())
     }
 
     /// Returns whether the pointer is aligned to `align`.
@@ -1950,7 +1948,7 @@ impl<T> *mut [T] {
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
-    /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
+    /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
     ///   and it must be properly aligned. This means in particular:
     ///
     ///     * The entire memory range of this slice must be contained within a single [allocated object]!
@@ -1962,7 +1960,7 @@ impl<T> *mut [T] {
     ///       them from other data. You can obtain a pointer that is usable as `data`
     ///       for zero-length slices using [`NonNull::dangling()`].
     ///
-    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
     ///   See the safety documentation of [`pointer::offset`].
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
@@ -2008,7 +2006,7 @@ impl<T> *mut [T] {
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
-    /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()`
+    /// * The pointer must be [valid] for reads and writes for `ptr.len() * size_of::<T>()`
     ///   many bytes, and it must be properly aligned. This means in particular:
     ///
     ///     * The entire memory range of this slice must be contained within a single [allocated object]!
@@ -2020,7 +2018,7 @@ impl<T> *mut [T] {
     ///       them from other data. You can obtain a pointer that is usable as `data`
     ///       for zero-length slices using [`NonNull::dangling()`].
     ///
-    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
     ///   See the safety documentation of [`pointer::offset`].
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 7abd3ddaa9e..c769ba673c6 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -49,7 +49,6 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
 /// are guaranteed to have the same size and alignment:
 ///
 /// ```
-/// # use std::mem::{size_of, align_of};
 /// use std::ptr::NonNull;
 ///
 /// assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>());
@@ -724,9 +723,9 @@ impl<T: ?Sized> NonNull<T> {
     }
 
     /// Calculates the distance between two pointers within the same allocation. The returned value is in
-    /// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
+    /// units of T: the distance in bytes divided by `size_of::<T>()`.
     ///
-    /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`,
+    /// This is equivalent to `(self as isize - origin as isize) / (size_of::<T>() as isize)`,
     /// except that it has a lot more opportunities for UB, in exchange for the compiler
     /// better understanding what you are doing.
     ///
@@ -762,7 +761,7 @@ impl<T: ?Sized> NonNull<T> {
     /// objects is not known at compile-time. However, the requirement also exists at
     /// runtime and may be exploited by optimizations. If you wish to compute the difference between
     /// pointers that are not guaranteed to be from the same allocation, use `(self as isize -
-    /// origin as isize) / mem::size_of::<T>()`.
+    /// origin as isize) / size_of::<T>()`.
     // FIXME: recommend `addr()` instead of `as usize` once that is stable.
     ///
     /// [`add`]: #method.add
@@ -842,7 +841,7 @@ impl<T: ?Sized> NonNull<T> {
 
     /// Calculates the distance between two pointers within the same allocation, *where it's known that
     /// `self` is equal to or greater than `origin`*. The returned value is in
-    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
+    /// units of T: the distance in bytes is divided by `size_of::<T>()`.
     ///
     /// This computes the same value that [`offset_from`](#method.offset_from)
     /// would compute, but with the added precondition that the offset is
@@ -989,7 +988,7 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { ptr::read_unaligned(self.as_ptr()) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+    /// Copies `count * size_of::<T>()` bytes from `self` to `dest`. The source
     /// and destination may overlap.
     ///
     /// NOTE: this has the *same* argument order as [`ptr::copy`].
@@ -1009,7 +1008,7 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { ptr::copy(self.as_ptr(), dest.as_ptr(), count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+    /// Copies `count * size_of::<T>()` bytes from `self` to `dest`. The source
     /// and destination may *not* overlap.
     ///
     /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`].
@@ -1029,7 +1028,7 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { ptr::copy_nonoverlapping(self.as_ptr(), dest.as_ptr(), count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `src` to `self`. The source
+    /// Copies `count * size_of::<T>()` bytes from `src` to `self`. The source
     /// and destination may overlap.
     ///
     /// NOTE: this has the *opposite* argument order of [`ptr::copy`].
@@ -1049,7 +1048,7 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { ptr::copy(src.as_ptr(), self.as_ptr(), count) }
     }
 
-    /// Copies `count * size_of<T>` bytes from `src` to `self`. The source
+    /// Copies `count * size_of::<T>()` bytes from `src` to `self`. The source
     /// and destination may *not* overlap.
     ///
     /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`].
@@ -1223,7 +1222,6 @@ impl<T: ?Sized> NonNull<T> {
     /// Accessing adjacent `u8` as `u16`
     ///
     /// ```
-    /// use std::mem::align_of;
     /// use std::ptr::NonNull;
     ///
     /// # unsafe {
@@ -1443,7 +1441,7 @@ impl<T> NonNull<[T]> {
     ///
     /// When calling this method, you have to ensure that all of the following is true:
     ///
-    /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
+    /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
     ///   and it must be properly aligned. This means in particular:
     ///
     ///     * The entire memory range of this slice must be contained within a single allocated object!
@@ -1455,7 +1453,7 @@ impl<T> NonNull<[T]> {
     ///       them from other data. You can obtain a pointer that is usable as `data`
     ///       for zero-length slices using [`NonNull::dangling()`].
     ///
-    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
     ///   See the safety documentation of [`pointer::offset`].
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
@@ -1488,7 +1486,7 @@ impl<T> NonNull<[T]> {
     ///
     /// When calling this method, you have to ensure that all of the following is true:
     ///
-    /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()`
+    /// * The pointer must be [valid] for reads and writes for `ptr.len() * size_of::<T>()`
     ///   many bytes, and it must be properly aligned. This means in particular:
     ///
     ///     * The entire memory range of this slice must be contained within a single allocated object!
@@ -1500,7 +1498,7 @@ impl<T> NonNull<[T]> {
     ///       them from other data. You can obtain a pointer that is usable as `data`
     ///       for zero-length slices using [`NonNull::dangling()`].
     ///
-    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
     ///   See the safety documentation of [`pointer::offset`].
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 92b5cba1531..ee98a47523f 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1744,6 +1744,14 @@ where
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T, E> crate::clone::UseCloned for Result<T, E>
+where
+    T: crate::clone::UseCloned,
+    E: crate::clone::UseCloned,
+{
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, E> IntoIterator for Result<T, E> {
     type Item = T;
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 9cb00644e64..804bdfcbb4f 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -1,10 +1,10 @@
 //! Comparison traits for `[T]`.
 
 use super::{from_raw_parts, memchr};
+use crate::ascii;
 use crate::cmp::{self, BytewiseEq, Ordering};
 use crate::intrinsics::compare_bytes;
 use crate::num::NonZero;
-use crate::{ascii, mem};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, U> PartialEq<[U]> for [T]
@@ -87,7 +87,7 @@ where
         // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
         // The two slices have been checked to have the same size above.
         unsafe {
-            let size = mem::size_of_val(self);
+            let size = size_of_val(self);
             compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
         }
     }
@@ -266,7 +266,7 @@ macro_rules! impl_slice_contains {
                 fn slice_contains(&self, arr: &[$t]) -> bool {
                     // Make our LANE_COUNT 4x the normal lane count (aiming for 128 bit vectors).
                     // The compiler will nicely unroll it.
-                    const LANE_COUNT: usize = 4 * (128 / (mem::size_of::<$t>() * 8));
+                    const LANE_COUNT: usize = 4 * (128 / (size_of::<$t>() * 8));
                     // SIMD
                     let mut chunks = arr.chunks_exact(LANE_COUNT);
                     for chunk in &mut chunks {
diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs
index 98db7aaf533..1e1053583a6 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -2,11 +2,10 @@
 // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
 use crate::intrinsics::const_eval_select;
-use crate::mem;
 
 const LO_USIZE: usize = usize::repeat_u8(0x01);
 const HI_USIZE: usize = usize::repeat_u8(0x80);
-const USIZE_BYTES: usize = mem::size_of::<usize>();
+const USIZE_BYTES: usize = size_of::<usize>();
 
 /// Returns `true` if `x` contains any zero byte.
 ///
@@ -138,7 +137,7 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
     // offset is always aligned, so just testing `>` is sufficient and avoids possible
     // overflow.
     let repeated_x = usize::repeat_u8(x);
-    let chunk_bytes = mem::size_of::<Chunk>();
+    let chunk_bytes = size_of::<Chunk>();
 
     while offset > min_aligned_offset {
         // SAFETY: offset starts at len - suffix.len(), as long as it is greater than
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index f991cc4ae2d..3570d8d0876 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3732,8 +3732,7 @@ impl<T> [T] {
     #[doc(alias = "memcpy")]
     #[inline]
     #[stable(feature = "copy_from_slice", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_copy_from_slice", issue = "131415")]
-    #[rustc_const_stable_indirect]
+    #[rustc_const_stable(feature = "const_copy_from_slice", since = "CURRENT_RUSTC_VERSION")]
     #[track_caller]
     pub const fn copy_from_slice(&mut self, src: &[T])
     where
@@ -3894,9 +3893,9 @@ impl<T> [T] {
 
         // Explicitly wrap the function call in a const block so it gets
         // constant-evaluated even in debug mode.
-        let gcd: usize = const { gcd(mem::size_of::<T>(), mem::size_of::<U>()) };
-        let ts: usize = mem::size_of::<U>() / gcd;
-        let us: usize = mem::size_of::<T>() / gcd;
+        let gcd: usize = const { gcd(size_of::<T>(), size_of::<U>()) };
+        let ts: usize = size_of::<U>() / gcd;
+        let us: usize = size_of::<T>() / gcd;
 
         // Armed with this knowledge, we can find how many `U`s we can fit!
         let us_len = self.len() / ts * us;
@@ -3946,7 +3945,7 @@ impl<T> [T] {
         // ptr.align_offset.
         let ptr = self.as_ptr();
         // SAFETY: See the `align_to_mut` method for the detailed safety comment.
-        let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::<U>()) };
+        let offset = unsafe { crate::ptr::align_offset(ptr, align_of::<U>()) };
         if offset > self.len() {
             (self, &[], &[])
         } else {
@@ -3956,7 +3955,7 @@ impl<T> [T] {
             #[cfg(miri)]
             crate::intrinsics::miri_promise_symbolic_alignment(
                 rest.as_ptr().cast(),
-                mem::align_of::<U>(),
+                align_of::<U>(),
             );
             // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay,
             // since the caller guarantees that we can transmute `T` to `U` safely.
@@ -4017,7 +4016,7 @@ impl<T> [T] {
         // valid pointer `ptr` (it comes from a reference to `self`) and with
         // a size that is a power of two (since it comes from the alignment for U),
         // satisfying its safety constraints.
-        let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::<U>()) };
+        let offset = unsafe { crate::ptr::align_offset(ptr, align_of::<U>()) };
         if offset > self.len() {
             (self, &mut [], &mut [])
         } else {
@@ -4029,7 +4028,7 @@ impl<T> [T] {
             #[cfg(miri)]
             crate::intrinsics::miri_promise_symbolic_alignment(
                 mut_ptr.cast() as *const (),
-                mem::align_of::<U>(),
+                align_of::<U>(),
             );
             // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`!
             // SAFETY: see comments for `align_to`.
@@ -4100,7 +4099,7 @@ impl<T> [T] {
         // These are expected to always match, as vector types are laid out like
         // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
         // might as well double-check since it'll optimize away anyhow.
-        assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
+        assert_eq!(size_of::<Simd<T, LANES>>(), size_of::<[T; LANES]>());
 
         // SAFETY: The simd types have the same layout as arrays, just with
         // potentially-higher alignment, so the de-facto transmutes are sound.
@@ -4136,7 +4135,7 @@ impl<T> [T] {
         // These are expected to always match, as vector types are laid out like
         // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
         // might as well double-check since it'll optimize away anyhow.
-        assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
+        assert_eq!(size_of::<Simd<T, LANES>>(), size_of::<[T; LANES]>());
 
         // SAFETY: The simd types have the same layout as arrays, just with
         // potentially-higher alignment, so the de-facto transmutes are sound.
@@ -4701,11 +4700,11 @@ impl<T> [T] {
 
         let byte_offset = elem_start.wrapping_sub(self_start);
 
-        if byte_offset % mem::size_of::<T>() != 0 {
+        if byte_offset % size_of::<T>() != 0 {
             return None;
         }
 
-        let offset = byte_offset / mem::size_of::<T>();
+        let offset = byte_offset / size_of::<T>();
 
         if offset < self.len() { Some(offset) } else { None }
     }
@@ -4755,11 +4754,11 @@ impl<T> [T] {
 
         let byte_start = subslice_start.wrapping_sub(self_start);
 
-        if byte_start % core::mem::size_of::<T>() != 0 {
+        if byte_start % size_of::<T>() != 0 {
             return None;
         }
 
-        let start = byte_start / core::mem::size_of::<T>();
+        let start = byte_start / size_of::<T>();
         let end = start.wrapping_add(subslice.len());
 
         if start <= self.len() && end <= self.len() { Some(start..end) } else { None }
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index e24b52cff82..3582c7e8b3f 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -11,7 +11,7 @@ use crate::{array, ptr, ub_checks};
 ///
 /// Behavior is undefined if any of the following conditions are violated:
 ///
-/// * `data` must be non-null, [valid] for reads for `len * mem::size_of::<T>()` many bytes,
+/// * `data` must be non-null, [valid] for reads for `len * size_of::<T>()` many bytes,
 ///   and it must be properly aligned. This means in particular:
 ///
 ///     * The entire memory range of this slice must be contained within a single allocated object!
@@ -28,7 +28,7 @@ use crate::{array, ptr, ub_checks};
 /// * The memory referenced by the returned slice must not be mutated for the duration
 ///   of lifetime `'a`, except inside an `UnsafeCell`.
 ///
-/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`,
+/// * The total size `len * size_of::<T>()` of the slice must be no larger than `isize::MAX`,
 ///   and adding that size to `data` must not "wrap around" the address space.
 ///   See the safety documentation of [`pointer::offset`].
 ///
@@ -146,7 +146,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 ///
 /// Behavior is undefined if any of the following conditions are violated:
 ///
-/// * `data` must be non-null, [valid] for both reads and writes for `len * mem::size_of::<T>()` many bytes,
+/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::<T>()` many bytes,
 ///   and it must be properly aligned. This means in particular:
 ///
 ///     * The entire memory range of this slice must be contained within a single allocated object!
@@ -163,7 +163,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 ///   (not derived from the return value) for the duration of lifetime `'a`.
 ///   Both read and write accesses are forbidden.
 ///
-/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`,
+/// * The total size `len * size_of::<T>()` of the slice must be no larger than `isize::MAX`,
 ///   and adding that size to `data` must not "wrap around" the address space.
 ///   See the safety documentation of [`pointer::offset`].
 ///
diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs
index 5d5ee4c7b62..80178f297ea 100644
--- a/library/core/src/slice/rotate.rs
+++ b/library/core/src/slice/rotate.rs
@@ -1,4 +1,4 @@
-use crate::mem::{self, MaybeUninit, SizedTypeProperties};
+use crate::mem::{MaybeUninit, SizedTypeProperties};
 use crate::{cmp, ptr};
 
 type BufType = [usize; 32];
@@ -21,12 +21,12 @@ pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
     }
     // `T` is not a zero-sized type, so it's okay to divide by its size.
     if !cfg!(feature = "optimize_for_size")
-        && cmp::min(left, right) <= mem::size_of::<BufType>() / mem::size_of::<T>()
+        && cmp::min(left, right) <= size_of::<BufType>() / size_of::<T>()
     {
         // SAFETY: guaranteed by the caller
         unsafe { ptr_rotate_memmove(left, mid, right) };
     } else if !cfg!(feature = "optimize_for_size")
-        && ((left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()))
+        && ((left + right < 24) || (size_of::<T>() > size_of::<[usize; 4]>()))
     {
         // SAFETY: guaranteed by the caller
         unsafe { ptr_rotate_gcd(left, mid, right) }
diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs
index f6dcf42ba60..95f196a40d0 100644
--- a/library/core/src/slice/sort/shared/smallsort.rs
+++ b/library/core/src/slice/sort/shared/smallsort.rs
@@ -113,7 +113,7 @@ pub(crate) trait UnstableSmallSortFreezeTypeImpl: Sized + FreezeMarker {
 impl<T: FreezeMarker> UnstableSmallSortFreezeTypeImpl for T {
     #[inline(always)]
     default fn small_sort_threshold() -> usize {
-        if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
+        if (size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
             SMALL_SORT_GENERAL_THRESHOLD
         } else {
             SMALL_SORT_FALLBACK_THRESHOLD
@@ -125,7 +125,7 @@ impl<T: FreezeMarker> UnstableSmallSortFreezeTypeImpl for T {
     where
         F: FnMut(&T, &T) -> bool,
     {
-        if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
+        if (size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
             small_sort_general(v, is_less);
         } else {
             small_sort_fallback(v, is_less);
@@ -143,10 +143,10 @@ impl<T: FreezeMarker + CopyMarker> UnstableSmallSortFreezeTypeImpl for T {
     #[inline(always)]
     fn small_sort_threshold() -> usize {
         if has_efficient_in_place_swap::<T>()
-            && (mem::size_of::<T>() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE
+            && (size_of::<T>() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE
         {
             SMALL_SORT_NETWORK_THRESHOLD
-        } else if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
+        } else if (size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
             SMALL_SORT_GENERAL_THRESHOLD
         } else {
             SMALL_SORT_FALLBACK_THRESHOLD
@@ -159,10 +159,10 @@ impl<T: FreezeMarker + CopyMarker> UnstableSmallSortFreezeTypeImpl for T {
         F: FnMut(&T, &T) -> bool,
     {
         if has_efficient_in_place_swap::<T>()
-            && (mem::size_of::<T>() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE
+            && (size_of::<T>() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE
         {
             small_sort_network(v, is_less);
-        } else if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
+        } else if (size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE {
             small_sort_general(v, is_less);
         } else {
             small_sort_fallback(v, is_less);
@@ -238,7 +238,7 @@ fn small_sort_general_with_scratch<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
     unsafe {
         let scratch_base = scratch.as_mut_ptr() as *mut T;
 
-        let presorted_len = if const { mem::size_of::<T>() <= 16 } && len >= 16 {
+        let presorted_len = if const { size_of::<T>() <= 16 } && len >= 16 {
             // SAFETY: scratch_base is valid and has enough space.
             sort8_stable(v_base, scratch_base, scratch_base.add(len), is_less);
             sort8_stable(
@@ -863,5 +863,5 @@ fn panic_on_ord_violation() -> ! {
 #[must_use]
 pub(crate) const fn has_efficient_in_place_swap<T>() -> bool {
     // Heuristic that holds true on all tested 64-bit capable architectures.
-    mem::size_of::<T>() <= 8 // mem::size_of::<u64>()
+    size_of::<T>() <= 8 // size_of::<u64>()
 }
diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs
index 3ff2e71fd05..090367cdaba 100644
--- a/library/core/src/slice/sort/stable/mod.rs
+++ b/library/core/src/slice/sort/stable/mod.rs
@@ -3,7 +3,7 @@
 #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
 use crate::cmp;
 use crate::intrinsics;
-use crate::mem::{self, MaybeUninit, SizedTypeProperties};
+use crate::mem::{MaybeUninit, SizedTypeProperties};
 #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
 use crate::slice::sort::shared::smallsort::{
     SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left,
@@ -107,7 +107,7 @@ fn driftsort_main<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], i
     // If min_good_run_len is ever modified, this code must be updated to allocate
     // the correct scratch size for it.
     const MAX_FULL_ALLOC_BYTES: usize = 8_000_000; // 8MB
-    let max_full_alloc = MAX_FULL_ALLOC_BYTES / mem::size_of::<T>();
+    let max_full_alloc = MAX_FULL_ALLOC_BYTES / size_of::<T>();
     let len = v.len();
     let alloc_len = cmp::max(
         cmp::max(len - len / 2, cmp::min(len, max_full_alloc)),
@@ -155,7 +155,7 @@ impl<T, const N: usize> AlignedStorage<T, N> {
     }
 
     fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<T>] {
-        let len = N / mem::size_of::<T>();
+        let len = N / size_of::<T>();
 
         // SAFETY: `_align` ensures we are correctly aligned.
         unsafe { core::slice::from_raw_parts_mut(self.storage.as_mut_ptr().cast(), len) }
diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs
index 630c6ff9077..3c9688790c4 100644
--- a/library/core/src/slice/sort/stable/quicksort.rs
+++ b/library/core/src/slice/sort/stable/quicksort.rs
@@ -1,6 +1,6 @@
 //! This module contains a stable quicksort and partition implementation.
 
-use crate::mem::{self, ManuallyDrop, MaybeUninit};
+use crate::mem::{ManuallyDrop, MaybeUninit};
 use crate::slice::sort::shared::FreezeMarker;
 use crate::slice::sort::shared::pivot::choose_pivot;
 use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl;
@@ -126,7 +126,7 @@ fn stable_partition<T, F: FnMut(&T, &T) -> bool>(
             // this gave significant performance boosts in benchmarks. Unrolling
             // through for _ in 0..UNROLL_LEN { .. } instead of manually improves
             // compile times but has a ~10-20% performance penalty on opt-level=s.
-            if const { mem::size_of::<T>() <= 16 } {
+            if const { size_of::<T>() <= 16 } {
                 const UNROLL_LEN: usize = 4;
                 let unroll_end = v_base.add(loop_end_pos.saturating_sub(UNROLL_LEN - 1));
                 while state.scan < unroll_end {
diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs
index bb9f90fc881..68a16118716 100644
--- a/library/core/src/slice/sort/unstable/quicksort.rs
+++ b/library/core/src/slice/sort/unstable/quicksort.rs
@@ -1,6 +1,8 @@
 //! This module contains an unstable quicksort and two partition implementations.
 
-use crate::mem::{self, ManuallyDrop};
+#[cfg(not(feature = "optimize_for_size"))]
+use crate::mem;
+use crate::mem::ManuallyDrop;
 #[cfg(not(feature = "optimize_for_size"))]
 use crate::slice::sort::shared::pivot::choose_pivot;
 #[cfg(not(feature = "optimize_for_size"))]
@@ -137,7 +139,7 @@ where
 
 const fn inst_partition<T, F: FnMut(&T, &T) -> bool>() -> fn(&mut [T], &T, &mut F) -> usize {
     const MAX_BRANCHLESS_PARTITION_SIZE: usize = 96;
-    if mem::size_of::<T>() <= MAX_BRANCHLESS_PARTITION_SIZE {
+    if size_of::<T>() <= MAX_BRANCHLESS_PARTITION_SIZE {
         // Specialize for types that are relatively cheap to copy, where branchless optimizations
         // have large leverage e.g. `u64` and `String`.
         cfg_if! {
@@ -304,7 +306,7 @@ where
 
         // Manual unrolling that works well on x86, Arm and with opt-level=s without murdering
         // compile-times. Leaving this to the compiler yields ok to bad results.
-        let unroll_len = const { if mem::size_of::<T>() <= 16 { 2 } else { 1 } };
+        let unroll_len = const { if size_of::<T>() <= 16 { 2 } else { 1 } };
 
         let unroll_end = v_base.add(len - (unroll_len - 1));
         while state.right < unroll_end {
diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs
index b5d7aaf05d4..452403b23de 100644
--- a/library/core/src/str/count.rs
+++ b/library/core/src/str/count.rs
@@ -20,7 +20,7 @@
 
 use core::intrinsics::unlikely;
 
-const USIZE_SIZE: usize = core::mem::size_of::<usize>();
+const USIZE_SIZE: usize = size_of::<usize>();
 const UNROLL_INNER: usize = 4;
 
 #[inline]
diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
index 0f724dd9613..8174e4ff97d 100644
--- a/library/core/src/str/validations.rs
+++ b/library/core/src/str/validations.rs
@@ -2,7 +2,6 @@
 
 use super::Utf8Error;
 use crate::intrinsics::const_eval_select;
-use crate::mem;
 
 /// Returns the initial codepoint accumulator for the first byte.
 /// The first byte is special, only want bottom 5 bits for width 2, 4 bits
@@ -128,7 +127,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
     let mut index = 0;
     let len = v.len();
 
-    const USIZE_BYTES: usize = mem::size_of::<usize>();
+    const USIZE_BYTES: usize = size_of::<usize>();
 
     let ascii_block_size = 2 * USIZE_BYTES;
     let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 73180bde54a..54a65c8459e 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -44,8 +44,9 @@
 //! The most important aspect of this model is that *data races* are undefined behavior. A data race
 //! is defined as conflicting non-synchronized accesses where at least one of the accesses is
 //! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at
-//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before*
-//! the other, according to the happens-before order of the memory model.
+//! least one of them is a write. (A `compare_exchange` or `compare_exchange_weak` that does not
+//! succeed is not considered a write.) They are *non-synchronized* if neither of them
+//! *happens-before* the other, according to the happens-before order of the memory model.
 //!
 //! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust
 //! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially
@@ -2033,7 +2034,7 @@ impl<T> AtomicPtr<T> {
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T {
-        self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order)
+        self.fetch_byte_add(val.wrapping_mul(size_of::<T>()), order)
     }
 
     /// Offsets the pointer's address by subtracting `val` (in units of `T`),
@@ -2078,7 +2079,7 @@ impl<T> AtomicPtr<T> {
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T {
-        self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order)
+        self.fetch_byte_sub(val.wrapping_mul(size_of::<T>()), order)
     }
 
     /// Offsets the pointer's address by adding `val` *bytes*, returning the
@@ -3997,24 +3998,24 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 ///
 /// A fence 'A' which has (at least) [`Release`] ordering semantics, synchronizes
 /// with a fence 'B' with (at least) [`Acquire`] semantics, if and only if there
-/// exist operations X and Y, both operating on some atomic object 'M' such
+/// exist operations X and Y, both operating on some atomic object 'm' such
 /// that A is sequenced before X, Y is sequenced before B and Y observes
-/// the change to M. This provides a happens-before dependence between A and B.
+/// the change to m. This provides a happens-before dependence between A and B.
 ///
 /// ```text
 ///     Thread 1                                          Thread 2
 ///
 /// fence(Release);      A --------------
-/// x.store(3, Relaxed); X ---------    |
+/// m.store(3, Relaxed); X ---------    |
 ///                                |    |
 ///                                |    |
-///                                -------------> Y  if x.load(Relaxed) == 3 {
+///                                -------------> Y  if m.load(Relaxed) == 3 {
 ///                                     |-------> B      fence(Acquire);
 ///                                                      ...
 ///                                                  }
 /// ```
 ///
-/// Note that in the example above, it is crucial that the accesses to `x` are atomic. Fences cannot
+/// Note that in the example above, it is crucial that the accesses to `m` are atomic. Fences cannot
 /// be used to establish synchronization among non-atomic accesses in different threads. However,
 /// thanks to the happens-before relationship between A and B, any non-atomic accesses that
 /// happen-before A are now also properly synchronized with any non-atomic accesses that
diff --git a/library/coretests/benches/ascii/is_ascii.rs b/library/coretests/benches/ascii/is_ascii.rs
index ced7084fb0e..a6c718409ee 100644
--- a/library/coretests/benches/ascii/is_ascii.rs
+++ b/library/coretests/benches/ascii/is_ascii.rs
@@ -95,7 +95,7 @@ benches! {
 // These are separate since it's easier to debug errors if they don't go through
 // macro expansion first.
 fn is_ascii_align_to(bytes: &[u8]) -> bool {
-    if bytes.len() < core::mem::size_of::<usize>() {
+    if bytes.len() < size_of::<usize>() {
         return bytes.iter().all(|b| b.is_ascii());
     }
     // SAFETY: transmuting a sequence of `u8` to `usize` is always fine
@@ -106,7 +106,7 @@ fn is_ascii_align_to(bytes: &[u8]) -> bool {
 }
 
 fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool {
-    if bytes.len() < core::mem::size_of::<usize>() {
+    if bytes.len() < size_of::<usize>() {
         return bytes.iter().all(|b| b.is_ascii());
     }
     // SAFETY: transmuting a sequence of `u8` to `[usize; 2]` is always fine
@@ -118,6 +118,6 @@ fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool {
 
 #[inline]
 fn contains_nonascii(v: usize) -> bool {
-    const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; core::mem::size_of::<usize>()]);
+    const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; size_of::<usize>()]);
     (NONASCII_MASK & v) != 0
 }
diff --git a/library/coretests/benches/iter.rs b/library/coretests/benches/iter.rs
index e14f26b7290..e49d152eb53 100644
--- a/library/coretests/benches/iter.rs
+++ b/library/coretests/benches/iter.rs
@@ -1,6 +1,5 @@
 use core::borrow::Borrow;
 use core::iter::*;
-use core::mem;
 use core::num::Wrapping;
 use core::ops::Range;
 
@@ -477,7 +476,7 @@ fn bench_next_chunk_copied(b: &mut Bencher) {
         let mut iter = black_box(&v).iter().copied();
         let mut acc = Wrapping(0);
         // This uses a while-let loop to side-step the TRA specialization in ArrayChunks
-        while let Ok(chunk) = iter.next_chunk::<{ mem::size_of::<u64>() }>() {
+        while let Ok(chunk) = iter.next_chunk::<{ size_of::<u64>() }>() {
             let d = u64::from_ne_bytes(chunk);
             acc += Wrapping(d.rotate_left(7).wrapping_add(1));
         }
@@ -496,7 +495,7 @@ fn bench_next_chunk_trusted_random_access(b: &mut Bencher) {
             .iter()
             // this shows that we're not relying on the slice::Iter specialization in Copied
             .map(|b| *b.borrow())
-            .array_chunks::<{ mem::size_of::<u64>() }>()
+            .array_chunks::<{ size_of::<u64>() }>()
             .map(|ary| {
                 let d = u64::from_ne_bytes(ary);
                 Wrapping(d.rotate_left(7).wrapping_add(1))
diff --git a/library/coretests/tests/alloc.rs b/library/coretests/tests/alloc.rs
index b88f1821cd7..72fdf82c1f8 100644
--- a/library/coretests/tests/alloc.rs
+++ b/library/coretests/tests/alloc.rs
@@ -1,5 +1,4 @@
 use core::alloc::Layout;
-use core::mem::size_of;
 use core::ptr::{self, NonNull};
 
 #[test]
diff --git a/library/coretests/tests/atomic.rs b/library/coretests/tests/atomic.rs
index 0ffba538b20..e0c0fe4790c 100644
--- a/library/coretests/tests/atomic.rs
+++ b/library/coretests/tests/atomic.rs
@@ -250,8 +250,6 @@ fn atomic_access_bool() {
 
 #[test]
 fn atomic_alignment() {
-    use std::mem::{align_of, size_of};
-
     #[cfg(target_has_atomic = "8")]
     assert_eq!(align_of::<AtomicBool>(), size_of::<AtomicBool>());
     #[cfg(target_has_atomic = "ptr")]
diff --git a/library/coretests/tests/hash/sip.rs b/library/coretests/tests/hash/sip.rs
index f79954f916b..6add1a33cb9 100644
--- a/library/coretests/tests/hash/sip.rs
+++ b/library/coretests/tests/hash/sip.rs
@@ -1,7 +1,7 @@
 #![allow(deprecated)]
 
 use core::hash::{Hash, Hasher, SipHasher, SipHasher13};
-use core::{mem, slice};
+use core::slice;
 
 // Hash just the bytes of the slice, without length prefix
 struct Bytes<'a>(&'a [u8]);
@@ -314,7 +314,7 @@ fn test_write_short_works() {
     h1.write_u8(0x01u8);
     let mut h2 = SipHasher::new();
     h2.write(unsafe {
-        slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::<usize>())
+        slice::from_raw_parts(&test_usize as *const _ as *const u8, size_of::<usize>())
     });
     h2.write(b"bytes");
     h2.write(b"string");
diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs
index bdc5701d9fd..00232c9b706 100644
--- a/library/coretests/tests/nonzero.rs
+++ b/library/coretests/tests/nonzero.rs
@@ -1,6 +1,5 @@
 use core::num::{IntErrorKind, NonZero};
 use core::option::Option::None;
-use std::mem::size_of;
 
 #[test]
 fn test_create_nonzero_instance() {
diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs
index c5fd7f01410..6091926084a 100644
--- a/library/coretests/tests/ptr.rs
+++ b/library/coretests/tests/ptr.rs
@@ -1,6 +1,6 @@
 use core::cell::RefCell;
 use core::marker::Freeze;
-use core::mem::{self, MaybeUninit};
+use core::mem::MaybeUninit;
 use core::num::NonZero;
 use core::ptr;
 use core::ptr::*;
@@ -388,7 +388,7 @@ fn align_offset_various_strides() {
         let mut expected = usize::MAX;
         // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
         for el in 0..align {
-            if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
+            if (numptr + el * size_of::<T>()) % align == 0 {
                 expected = el;
                 break;
             }
@@ -398,7 +398,7 @@ fn align_offset_various_strides() {
             eprintln!(
                 "aligning {:p} (with stride of {}) to {}, expected {}, got {}",
                 ptr,
-                ::std::mem::size_of::<T>(),
+                size_of::<T>(),
                 align,
                 expected,
                 got
@@ -605,9 +605,9 @@ fn dyn_metadata() {
     let meta = metadata(trait_object);
 
     assert_eq!(meta.size_of(), 64);
-    assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
+    assert_eq!(meta.size_of(), size_of::<Something>());
     assert_eq!(meta.align_of(), 32);
-    assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
+    assert_eq!(meta.align_of(), align_of::<Something>());
     assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
 
     assert!(format!("{meta:?}").starts_with("DynMetadata(0x"));
@@ -781,7 +781,7 @@ fn nonnull_tagged_pointer_with_provenance() {
 
     impl<T> TaggedPointer<T> {
         /// The ABI-required minimum alignment of the `P` type.
-        pub const ALIGNMENT: usize = core::mem::align_of::<T>();
+        pub const ALIGNMENT: usize = align_of::<T>();
         /// A mask for data-carrying bits of the address.
         pub const DATA_MASK: usize = !Self::ADDRESS_MASK;
         /// Number of available bits of storage in the address.
@@ -865,7 +865,7 @@ fn test_const_copy_ptr() {
             ptr::copy(
                 &ptr1 as *const _ as *const MaybeUninit<u8>,
                 &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
-                mem::size_of::<&i32>(),
+                size_of::<&i32>(),
             );
         }
 
@@ -883,7 +883,7 @@ fn test_const_copy_ptr() {
             ptr::copy_nonoverlapping(
                 &ptr1 as *const _ as *const MaybeUninit<u8>,
                 &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
-                mem::size_of::<&i32>(),
+                size_of::<&i32>(),
             );
         }
 
@@ -928,7 +928,7 @@ fn test_const_swap_ptr() {
         let mut s2 = A(S { ptr: &666, f1: 0, f2: [0; 3] });
 
         // Swap ptr1 and ptr2, as an array.
-        type T = [u8; mem::size_of::<A>()];
+        type T = [u8; size_of::<A>()];
         unsafe {
             ptr::swap(ptr::from_mut(&mut s1).cast::<T>(), ptr::from_mut(&mut s2).cast::<T>());
         }
diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs
index fe356dcc43c..d17e681480c 100644
--- a/library/coretests/tests/slice.rs
+++ b/library/coretests/tests/slice.rs
@@ -2057,15 +2057,13 @@ fn test_align_to_non_trivial() {
 
 #[test]
 fn test_align_to_empty_mid() {
-    use core::mem;
-
     // Make sure that we do not create empty unaligned slices for the mid part, even when the
     // overall slice is too short to contain an aligned address.
     let bytes = [1, 2, 3, 4, 5, 6, 7];
     type Chunk = u32;
     for offset in 0..4 {
         let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::<Chunk>() };
-        assert_eq!(mid.as_ptr() as usize % mem::align_of::<Chunk>(), 0);
+        assert_eq!(mid.as_ptr() as usize % align_of::<Chunk>(), 0);
     }
 }
 
diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs
index 1569c26c9de..bad795a019c 100644
--- a/library/panic_unwind/src/emcc.rs
+++ b/library/panic_unwind/src/emcc.rs
@@ -9,7 +9,7 @@
 use alloc::boxed::Box;
 use core::any::Any;
 use core::sync::atomic::{AtomicBool, Ordering};
-use core::{intrinsics, mem, ptr};
+use core::{intrinsics, ptr};
 
 use unwind as uw;
 
@@ -97,7 +97,7 @@ pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
 
 pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     unsafe {
-        let exception = __cxa_allocate_exception(mem::size_of::<Exception>()) as *mut Exception;
+        let exception = __cxa_allocate_exception(size_of::<Exception>()) as *mut Exception;
         if exception.is_null() {
             return uw::_URC_FATAL_PHASE1_ERROR as u32;
         }
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index 3a95b940221..3794b56c089 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -49,7 +49,7 @@
 use alloc::boxed::Box;
 use core::any::Any;
 use core::ffi::{c_int, c_uint, c_void};
-use core::mem::{self, ManuallyDrop};
+use core::mem::ManuallyDrop;
 
 // NOTE(nbdd0121): The `canary` field is part of stable ABI.
 #[repr(C)]
@@ -225,7 +225,7 @@ static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
     properties: 0,
     pType: ptr_t::null(),
     thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 },
-    sizeOrOffset: mem::size_of::<Exception>() as c_int,
+    sizeOrOffset: size_of::<Exception>() as c_int,
     copyFunction: ptr_t::null(),
 };
 
diff --git a/library/proc_macro/src/bridge/selfless_reify.rs b/library/proc_macro/src/bridge/selfless_reify.rs
index 312a79152e2..b06434a5ffe 100644
--- a/library/proc_macro/src/bridge/selfless_reify.rs
+++ b/library/proc_macro/src/bridge/selfless_reify.rs
@@ -50,7 +50,7 @@ macro_rules! define_reify_functions {
         >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {
             // FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic
             // formatting becomes possible in `const fn`.
-            assert!(mem::size_of::<F>() == 0, "selfless_reify: closure must be zero-sized");
+            assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized");
 
             $(extern $abi)? fn wrapper<
                 $($($param,)*)?
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 0ec167c2d16..f7379c413f1 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -73,7 +73,7 @@ fortanix-sgx-abi = { version = "0.5.0", features = [
 ], public = true }
 
 [target.'cfg(target_os = "hermit")'.dependencies]
-hermit-abi = { version = "0.4.0", features = [
+hermit-abi = { version = "0.5.0", features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/library/std/build.rs b/library/std/build.rs
index 9df35ce3cc8..cedfd7406a1 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -113,7 +113,6 @@ fn main() {
         // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
         ("csky", _) => false,
         ("hexagon", _) => false,
-        ("loongarch64", _) => false,
         ("powerpc" | "powerpc64", _) => false,
         ("sparc" | "sparc64", _) => false,
         ("wasm32" | "wasm64", _) => false,
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index e62aeb2ede0..6961fa8ea94 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -202,6 +202,9 @@ impl fmt::Debug for VarsOs {
 /// Returns [`VarError::NotUnicode`] if the variable's value is not valid
 /// Unicode. If this is not desired, consider using [`var_os`].
 ///
+/// Use [`env!`] or [`option_env!`] instead if you want to check environment
+/// variables at compile time.
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index f4a02802336..aa25ff5293c 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -257,7 +257,30 @@ impl OsString {
     #[inline]
     #[rustc_confusables("append", "put")]
     pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
-        self.inner.push_slice(&s.as_ref().inner)
+        trait SpecPushTo {
+            fn spec_push_to(&self, buf: &mut OsString);
+        }
+
+        impl<T: AsRef<OsStr>> SpecPushTo for T {
+            #[inline]
+            default fn spec_push_to(&self, buf: &mut OsString) {
+                buf.inner.push_slice(&self.as_ref().inner);
+            }
+        }
+
+        // Use a more efficient implementation when the string is UTF-8.
+        macro spec_str($T:ty) {
+            impl SpecPushTo for $T {
+                #[inline]
+                fn spec_push_to(&self, buf: &mut OsString) {
+                    buf.inner.push_str(self);
+                }
+            }
+        }
+        spec_str!(str);
+        spec_str!(String);
+
+        s.spec_push_to(self)
     }
 
     /// Creates a new `OsString` with at least the given capacity.
@@ -587,7 +610,30 @@ impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
     /// Copies any value implementing <code>[AsRef]&lt;[OsStr]&gt;</code>
     /// into a newly allocated [`OsString`].
     fn from(s: &T) -> OsString {
-        s.as_ref().to_os_string()
+        trait SpecToOsString {
+            fn spec_to_os_string(&self) -> OsString;
+        }
+
+        impl<T: AsRef<OsStr>> SpecToOsString for T {
+            #[inline]
+            default fn spec_to_os_string(&self) -> OsString {
+                self.as_ref().to_os_string()
+            }
+        }
+
+        // Preserve the known-UTF-8 property for strings.
+        macro spec_str($T:ty) {
+            impl SpecToOsString for $T {
+                #[inline]
+                fn spec_to_os_string(&self) -> OsString {
+                    OsString::from(String::from(self))
+                }
+            }
+        }
+        spec_str!(str);
+        spec_str!(String);
+
+        s.spec_to_os_string()
     }
 }
 
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 4314c8a0b18..46b5860123f 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2446,7 +2446,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `rename` function on Unix
-/// and the `SetFileInformationByHandle` function on Windows.
+/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows.
 ///
 /// Because of this, the behavior when both `from` and `to` exist differs. On
 /// Unix, if `from` is a directory, `to` must also be an (empty) directory. If
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 38dcd816d26..6dd18e4f4c8 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1878,7 +1878,7 @@ fn windows_unix_socket_exists() {
         let bytes = socket_path.as_os_str().as_encoded_bytes();
         let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::<i8>(), bytes.len());
         addr.sun_path[..bytes.len()].copy_from_slice(bytes);
-        let len = mem::size_of_val(&addr) as i32;
+        let len = size_of_val(&addr) as i32;
         let result = c::bind(socket, (&raw const addr).cast::<c::SOCKADDR>(), len);
         c::closesocket(socket);
         assert_eq!(result, 0);
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 8b46738ab8a..697fb5974a3 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -118,16 +118,16 @@ impl<R: Read + ?Sized> BufReader<R> {
     /// #![feature(bufreader_peek)]
     /// use std::io::{Read, BufReader};
     ///
-    /// let mut bytes = &b"oh, hello"[..];
+    /// let mut bytes = &b"oh, hello there"[..];
     /// let mut rdr = BufReader::with_capacity(6, &mut bytes);
     /// assert_eq!(rdr.peek(2).unwrap(), b"oh");
     /// let mut buf = [0; 4];
     /// rdr.read(&mut buf[..]).unwrap();
     /// assert_eq!(&buf, b"oh, ");
-    /// assert_eq!(rdr.peek(2).unwrap(), b"he");
+    /// assert_eq!(rdr.peek(5).unwrap(), b"hello");
     /// let mut s = String::new();
     /// rdr.read_to_string(&mut s).unwrap();
-    /// assert_eq!(&s, "hello");
+    /// assert_eq!(&s, "hello there");
     /// assert_eq!(rdr.peek(1).unwrap().len(), 0);
     /// ```
     #[unstable(feature = "bufreader_peek", issue = "128405")]
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 5251cc302cb..9fd2472ebdf 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -109,8 +109,8 @@ impl Buffer {
 
     /// Read more bytes into the buffer without discarding any of its contents
     pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<usize> {
-        let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]);
-        let old_init = self.initialized - self.pos;
+        let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]);
+        let old_init = self.initialized - self.filled;
         unsafe {
             buf.set_init(old_init);
         }
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 08832bbc1e3..d7131e2fe92 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -439,6 +439,27 @@ fn slice_write_vectored(
     Ok(nwritten)
 }
 
+#[inline]
+fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> {
+    let n = slice_write(pos_mut, slice, buf)?;
+    if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
+}
+
+#[inline]
+fn slice_write_all_vectored(
+    pos_mut: &mut u64,
+    slice: &mut [u8],
+    bufs: &[IoSlice<'_>],
+) -> io::Result<()> {
+    for buf in bufs {
+        let n = slice_write(pos_mut, slice, buf)?;
+        if n < buf.len() {
+            return Err(io::Error::WRITE_ALL_EOF);
+        }
+    }
+    Ok(())
+}
+
 /// Reserves the required space, and pads the vec with 0s if necessary.
 fn reserve_and_pad<A: Allocator>(
     pos_mut: &mut u64,
@@ -481,9 +502,12 @@ fn reserve_and_pad<A: Allocator>(
     Ok(pos)
 }
 
-/// Writes the slice to the vec without allocating
-/// # Safety: vec must have buf.len() spare capacity
-unsafe fn vec_write_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize
+/// Writes the slice to the vec without allocating.
+///
+/// # Safety
+///
+/// `vec` must have `buf.len()` spare capacity.
+unsafe fn vec_write_all_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize
 where
     A: Allocator,
 {
@@ -492,7 +516,7 @@ where
     pos + buf.len()
 }
 
-/// Resizing write implementation for [`Cursor`]
+/// Resizing `write_all` implementation for [`Cursor`].
 ///
 /// Cursor is allowed to have a pre-allocated and initialised
 /// vector body, but with a position of 0. This means the [`Write`]
@@ -501,7 +525,7 @@ where
 /// This also allows for the vec body to be empty, but with a position of N.
 /// This means that [`Write`] will pad the vec with 0 initially,
 /// before writing anything from that point
-fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
+fn vec_write_all<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
 where
     A: Allocator,
 {
@@ -512,7 +536,7 @@ where
     // Safety: we have ensured that the capacity is available
     // and that all bytes get written up to pos
     unsafe {
-        pos = vec_write_unchecked(pos, vec, buf);
+        pos = vec_write_all_unchecked(pos, vec, buf);
         if pos > vec.len() {
             vec.set_len(pos);
         }
@@ -523,7 +547,7 @@ where
     Ok(buf_len)
 }
 
-/// Resizing write_vectored implementation for [`Cursor`]
+/// Resizing `write_all_vectored` implementation for [`Cursor`].
 ///
 /// Cursor is allowed to have a pre-allocated and initialised
 /// vector body, but with a position of 0. This means the [`Write`]
@@ -532,7 +556,7 @@ where
 /// This also allows for the vec body to be empty, but with a position of N.
 /// This means that [`Write`] will pad the vec with 0 initially,
 /// before writing anything from that point
-fn vec_write_vectored<A>(
+fn vec_write_all_vectored<A>(
     pos_mut: &mut u64,
     vec: &mut Vec<u8, A>,
     bufs: &[IoSlice<'_>],
@@ -550,7 +574,7 @@ where
     // and that all bytes get written up to the last pos
     unsafe {
         for buf in bufs {
-            pos = vec_write_unchecked(pos, vec, buf);
+            pos = vec_write_all_unchecked(pos, vec, buf);
         }
         if pos > vec.len() {
             vec.set_len(pos);
@@ -580,6 +604,16 @@ impl Write for Cursor<&mut [u8]> {
     }
 
     #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        slice_write_all(&mut self.pos, self.inner, buf)
+    }
+
+    #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        slice_write_all_vectored(&mut self.pos, self.inner, bufs)
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -591,11 +625,11 @@ where
     A: Allocator,
 {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        vec_write(&mut self.pos, self.inner, buf)
+        vec_write_all(&mut self.pos, self.inner, buf)
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        vec_write_vectored(&mut self.pos, self.inner, bufs)
+        vec_write_all_vectored(&mut self.pos, self.inner, bufs)
     }
 
     #[inline]
@@ -603,6 +637,16 @@ where
         true
     }
 
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        vec_write_all(&mut self.pos, self.inner, buf)?;
+        Ok(())
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        vec_write_all_vectored(&mut self.pos, self.inner, bufs)?;
+        Ok(())
+    }
+
     #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
@@ -615,11 +659,11 @@ where
     A: Allocator,
 {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        vec_write(&mut self.pos, &mut self.inner, buf)
+        vec_write_all(&mut self.pos, &mut self.inner, buf)
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        vec_write_vectored(&mut self.pos, &mut self.inner, bufs)
+        vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)
     }
 
     #[inline]
@@ -627,6 +671,16 @@ where
         true
     }
 
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        vec_write_all(&mut self.pos, &mut self.inner, buf)?;
+        Ok(())
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)?;
+        Ok(())
+    }
+
     #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
@@ -654,6 +708,16 @@ where
     }
 
     #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        slice_write_all(&mut self.pos, &mut self.inner, buf)
+    }
+
+    #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs)
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -677,6 +741,16 @@ impl<const N: usize> Write for Cursor<[u8; N]> {
     }
 
     #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        slice_write_all(&mut self.pos, &mut self.inner, buf)
+    }
+
+    #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs)
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index edac6563478..3e4029768eb 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -1,6 +1,5 @@
 use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error};
 use crate::assert_matches::assert_matches;
-use crate::mem::size_of;
 use crate::sys::decode_error_kind;
 use crate::sys::os::error_string;
 use crate::{error, fmt};
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 8239b29884e..d0245f3d498 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -455,7 +455,17 @@ impl Write for &mut [u8] {
 
     #[inline]
     fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
-        if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) }
+        if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
+    }
+
+    #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        for buf in bufs {
+            if self.write(buf)? < buf.len() {
+                return Err(io::Error::WRITE_ALL_EOF);
+            }
+        }
+        Ok(())
     }
 
     #[inline]
@@ -496,6 +506,12 @@ impl<A: Allocator> Write for Vec<u8, A> {
     }
 
     #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.write_vectored(bufs)?;
+        Ok(())
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -515,6 +531,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
         Ok(n)
     }
 
+    #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         let (front, back) = self.as_slices();
 
@@ -547,6 +564,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
         Ok(())
     }
 
+    #[inline]
     fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         let len = cursor.capacity();
         let (front, back) = self.as_slices();
@@ -639,6 +657,12 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
     }
 
     #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.write_vectored(bufs)?;
+        Ok(())
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -646,6 +670,7 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
 
 #[unstable(feature = "read_buf", issue = "78485")]
 impl<'a> io::Write for core::io::BorrowedCursor<'a> {
+    #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         let amt = cmp::min(buf.len(), self.capacity());
         self.append(&buf[..amt]);
@@ -653,6 +678,39 @@ impl<'a> io::Write for core::io::BorrowedCursor<'a> {
     }
 
     #[inline]
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let mut nwritten = 0;
+        for buf in bufs {
+            let n = self.write(buf)?;
+            nwritten += n;
+            if n < buf.len() {
+                break;
+            }
+        }
+        Ok(nwritten)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
+    }
+
+    #[inline]
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        for buf in bufs {
+            if self.write(buf)? < buf.len() {
+                return Err(io::Error::WRITE_ALL_EOF);
+            }
+        }
+        Ok(())
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index bdd330611de..5ac3dbc3e98 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2121,8 +2121,8 @@ mod unsafe_keyword {}
 
 #[doc(keyword = "use")]
 //
-/// Import or rename items from other crates or modules, or specify precise capturing
-/// with `use<..>`.
+/// Import or rename items from other crates or modules, use values under ergonomic clones
+/// semantic, or specify precise capturing with `use<..>`.
 ///
 /// ## Importing items
 ///
@@ -2205,6 +2205,11 @@ mod unsafe_keyword {}
 ///
 /// For more details about precise capturing, see the [Reference][ref-impl-trait].
 ///
+/// ## Ergonomic clones
+///
+/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the
+/// value implements `UseCloned` or moving it otherwise.
+///
 /// [`crate`]: keyword.crate.html
 /// [`self`]: keyword.self.html
 /// [`super`]: keyword.super.html
diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs
index b39863644f1..7e9cf038e9a 100644
--- a/library/std/src/os/fd/tests.rs
+++ b/library/std/src/os/fd/tests.rs
@@ -36,7 +36,6 @@ fn test_fd() {
 #[cfg(any(unix, target_os = "wasi"))]
 #[test]
 fn test_niche_optimizations() {
-    use crate::mem::size_of;
     #[cfg(unix)]
     use crate::os::unix::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
     #[cfg(target_os = "wasi")]
diff --git a/library/std/src/os/unix/io/tests.rs b/library/std/src/os/unix/io/tests.rs
index 84d2a7a1a91..fc147730578 100644
--- a/library/std/src/os/unix/io/tests.rs
+++ b/library/std/src/os/unix/io/tests.rs
@@ -1,4 +1,3 @@
-use crate::mem::size_of;
 use crate::os::unix::io::RawFd;
 
 #[test]
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index 56789f235fd..cb1246db310 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -94,7 +94,7 @@ impl SocketAddr {
     {
         unsafe {
             let mut addr: libc::sockaddr_un = mem::zeroed();
-            let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+            let mut len = size_of::<libc::sockaddr_un>() as libc::socklen_t;
             cvt(f((&raw mut addr) as *mut _, &mut len))?;
             SocketAddr::from_parts(addr, len)
         }
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index be236317d04..27428c9eb28 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -177,7 +177,7 @@ impl UnixListener {
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
         let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
-        let mut len = mem::size_of_val(&storage) as libc::socklen_t;
+        let mut len = size_of_val(&storage) as libc::socklen_t;
         let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?;
         let addr = SocketAddr::from_parts(storage, len)?;
         Ok((UnixStream(sock), addr))
diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs
index e1014a4f296..2dd7d409e48 100644
--- a/library/std/src/os/unix/net/ucred.rs
+++ b/library/std/src/os/unix/net/ucred.rs
@@ -41,15 +41,15 @@ mod impl_linux {
     use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred};
 
     use super::UCred;
+    use crate::io;
     use crate::os::unix::io::AsRawFd;
     use crate::os::unix::net::UnixStream;
-    use crate::{io, mem};
 
     pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
-        let ucred_size = mem::size_of::<ucred>();
+        let ucred_size = size_of::<ucred>();
 
         // Trivial sanity checks.
-        assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+        assert!(size_of::<u32>() <= size_of::<usize>());
         assert!(ucred_size <= u32::MAX as usize);
 
         let mut ucred_size = ucred_size as socklen_t;
@@ -64,7 +64,7 @@ mod impl_linux {
                 &mut ucred_size,
             );
 
-            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+            if ret == 0 && ucred_size as usize == size_of::<ucred>() {
                 Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
             } else {
                 Err(io::Error::last_os_error())
@@ -101,9 +101,9 @@ mod impl_apple {
     use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t};
 
     use super::UCred;
+    use crate::io;
     use crate::os::unix::io::AsRawFd;
     use crate::os::unix::net::UnixStream;
-    use crate::{io, mem};
 
     pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
         let mut cred = UCred { uid: 1, gid: 1, pid: None };
@@ -115,7 +115,7 @@ mod impl_apple {
             }
 
             let mut pid: pid_t = 1;
-            let mut pid_size = mem::size_of::<pid_t>() as socklen_t;
+            let mut pid_size = size_of::<pid_t>() as socklen_t;
 
             let ret = getsockopt(
                 socket.as_raw_fd(),
@@ -125,7 +125,7 @@ mod impl_apple {
                 &mut pid_size,
             );
 
-            if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
+            if ret == 0 && pid_size as usize == size_of::<pid_t>() {
                 cred.pid = Some(pid);
                 Ok(cred)
             } else {
diff --git a/library/std/src/os/wasi/io/tests.rs b/library/std/src/os/wasi/io/tests.rs
index 418274752b0..c5c6a19a6c8 100644
--- a/library/std/src/os/wasi/io/tests.rs
+++ b/library/std/src/os/wasi/io/tests.rs
@@ -1,4 +1,3 @@
-use crate::mem::size_of;
 use crate::os::wasi::io::RawFd;
 
 #[test]
diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs
index 41734e52e8c..029b6f5cd3d 100644
--- a/library/std/src/os/windows/io/tests.rs
+++ b/library/std/src/os/windows/io/tests.rs
@@ -1,6 +1,5 @@
 #[test]
 fn test_niche_optimizations_socket() {
-    use crate::mem::size_of;
     use crate::os::windows::io::{
         BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
     };
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 201274cf03a..fa65a7c51bf 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -500,11 +500,7 @@ impl<'a> ProcThreadAttributeListBuilder<'a> {
     /// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute#parameters>
     pub fn attribute<T>(self, attribute: usize, value: &'a T) -> Self {
         unsafe {
-            self.raw_attribute(
-                attribute,
-                ptr::addr_of!(*value).cast::<c_void>(),
-                crate::mem::size_of::<T>(),
-            )
+            self.raw_attribute(attribute, ptr::addr_of!(*value).cast::<c_void>(), size_of::<T>())
         }
     }
 
@@ -574,7 +570,7 @@ impl<'a> ProcThreadAttributeListBuilder<'a> {
     ///         .raw_attribute(
     ///             PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
     ///             h_pc as *const c_void,
-    ///             std::mem::size_of::<isize>(),
+    ///             size_of::<isize>(),
     ///         )
     ///         .finish()?
     /// };
diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
index 1db314e9dda..9394f0a0496 100644
--- a/library/std/src/os/xous/ffi.rs
+++ b/library/std/src/os/xous/ffi.rs
@@ -368,7 +368,7 @@ pub(crate) unsafe fn map_memory<T>(
     let mut a0 = Syscall::MapMemory as usize;
     let mut a1 = phys.map(|p| p.as_ptr() as usize).unwrap_or_default();
     let mut a2 = virt.map(|p| p.as_ptr() as usize).unwrap_or_default();
-    let a3 = count * core::mem::size_of::<T>();
+    let a3 = count * size_of::<T>();
     let a4 = flags.bits();
     let a5 = 0;
     let a6 = 0;
@@ -392,7 +392,7 @@ pub(crate) unsafe fn map_memory<T>(
 
     if result == SyscallResult::MemoryRange as usize {
         let start = core::ptr::with_exposed_provenance_mut::<T>(a1);
-        let len = a2 / core::mem::size_of::<T>();
+        let len = a2 / size_of::<T>();
         let end = unsafe { start.add(len) };
         Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
     } else if result == SyscallResult::Error as usize {
@@ -409,7 +409,7 @@ pub(crate) unsafe fn map_memory<T>(
 pub(crate) unsafe fn unmap_memory<T>(range: *mut [T]) -> Result<(), Error> {
     let mut a0 = Syscall::UnmapMemory as usize;
     let mut a1 = range.as_mut_ptr() as usize;
-    let a2 = range.len() * core::mem::size_of::<T>();
+    let a2 = range.len() * size_of::<T>();
     let a3 = 0;
     let a4 = 0;
     let a5 = 0;
@@ -455,7 +455,7 @@ pub(crate) unsafe fn update_memory_flags<T>(
 ) -> Result<(), Error> {
     let mut a0 = Syscall::UpdateMemoryFlags as usize;
     let mut a1 = range.as_mut_ptr() as usize;
-    let a2 = range.len() * core::mem::size_of::<T>();
+    let a2 = range.len() * size_of::<T>();
     let a3 = new_flags.bits();
     let a4 = 0; // Process ID is currently None
     let a5 = 0;
diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs
index 1661011ca64..095d4f4a3e7 100644
--- a/library/std/src/os/xous/services/log.rs
+++ b/library/std/src/os/xous/services/log.rs
@@ -7,8 +7,8 @@ use crate::os::xous::ffi::Connection;
 /// `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will return a
 /// `usize` with 5678 packed into it.
 fn group_or_null(data: &[u8], offset: usize) -> usize {
-    let start = offset * core::mem::size_of::<usize>();
-    let mut out_array = [0u8; core::mem::size_of::<usize>()];
+    let start = offset * size_of::<usize>();
+    let mut out_array = [0u8; size_of::<usize>()];
     if start < data.len() {
         for (dest, src) in out_array.iter_mut().zip(&data[start..]) {
             *dest = *src;
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index 992a9207a72..5f7097c26e2 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -160,3 +160,18 @@ pub mod rust_2024 {
     #[doc(no_inline)]
     pub use core::prelude::rust_2024::*;
 }
+
+/// The Future version of the prelude of The Rust Standard Library.
+///
+/// See the [module-level documentation](self) for more.
+#[doc(hidden)]
+#[unstable(feature = "prelude_future", issue = "none")]
+pub mod rust_future {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[doc(no_inline)]
+    pub use super::v1::*;
+
+    #[unstable(feature = "prelude_next", issue = "none")]
+    #[doc(no_inline)]
+    pub use core::prelude::rust_future::*;
+}
diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs
index 1af9d766290..a7ac4117ec9 100644
--- a/library/std/src/sys/alloc/unix.rs
+++ b/library/std/src/sys/alloc/unix.rs
@@ -81,7 +81,7 @@ cfg_if::cfg_if! {
             // while others require the alignment to be at least the pointer size (Illumos, macOS).
             // posix_memalign only has one, clear requirement: that the alignment be a multiple of
             // `sizeof(void*)`. Since these are all powers of 2, we can just use max.
-            let align = layout.align().max(crate::mem::size_of::<usize>());
+            let align = layout.align().max(size_of::<usize>());
             let ret = unsafe { libc::posix_memalign(&mut out, align, layout.size()) };
             if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
         }
diff --git a/library/std/src/sys/alloc/windows/tests.rs b/library/std/src/sys/alloc/windows/tests.rs
index 674a3e1d92d..1d5614528b1 100644
--- a/library/std/src/sys/alloc/windows/tests.rs
+++ b/library/std/src/sys/alloc/windows/tests.rs
@@ -1,9 +1,8 @@
 use super::{Header, MIN_ALIGN};
-use crate::mem;
 
 #[test]
 fn alloc_header() {
     // Header must fit in the padding before an aligned pointer
-    assert!(mem::size_of::<Header>() <= MIN_ALIGN);
-    assert!(mem::align_of::<Header>() <= MIN_ALIGN);
+    assert!(size_of::<Header>() <= MIN_ALIGN);
+    assert!(align_of::<Header>() <= MIN_ALIGN);
 }
diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys/fs/common.rs
index bfd684d295b..bfd684d295b 100644
--- a/library/std/src/sys_common/fs.rs
+++ b/library/std/src/sys/fs/common.rs
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/fs/hermit.rs
index d4bf84dc185..f83a2f90ed2 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -1,18 +1,18 @@
-use super::fd::FileDesc;
-use super::hermit_abi::{
-    self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY,
-    O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct,
-};
 use crate::ffi::{CStr, OsStr, OsString, c_char};
 use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
 use crate::os::hermit::ffi::OsStringExt;
+use crate::os::hermit::hermit_abi::{
+    self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY,
+    O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct,
+};
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::path::{Path, PathBuf};
 use crate::sync::Arc;
 use crate::sys::common::small_c_string::run_path_with_cstr;
+pub use crate::sys::fs::common::{copy, exists};
+use crate::sys::pal::fd::FileDesc;
 use crate::sys::time::SystemTime;
 use crate::sys::{cvt, unsupported};
-pub use crate::sys_common::fs::{copy, exists};
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{fmt, mem};
 
@@ -396,7 +396,7 @@ impl File {
     }
 
     pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
-        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+        self.0.read_buf(cursor)
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
@@ -417,12 +417,12 @@ impl File {
         Ok(())
     }
 
-    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
-        Err(Error::from_raw_os_error(22))
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        self.0.seek(pos)
     }
 
     pub fn tell(&self) -> io::Result<u64> {
-        self.seek(SeekFrom::Current(0))
+        self.0.tell()
     }
 
     pub fn duplicate(&self) -> io::Result<File> {
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
new file mode 100644
index 00000000000..c2e19eb393a
--- /dev/null
+++ b/library/std/src/sys/fs/mod.rs
@@ -0,0 +1,28 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+pub mod common;
+
+cfg_if::cfg_if! {
+    if #[cfg(target_family = "unix")] {
+        mod unix;
+        pub use unix::*;
+    } else if #[cfg(target_os = "windows")] {
+        mod windows;
+        pub use windows::*;
+    } else if #[cfg(target_os = "hermit")] {
+        mod hermit;
+        pub use hermit::*;
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod solid;
+        pub use solid::*;
+    } else if #[cfg(target_os = "uefi")] {
+        mod uefi;
+        pub use uefi::*;
+    } else if #[cfg(target_os = "wasi")] {
+        mod wasi;
+        pub use wasi::*;
+    } else {
+        mod unsupported;
+        pub use unsupported::*;
+    }
+}
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/fs/solid.rs
index 4e741943283..39de933b724 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/fs/solid.rs
@@ -1,4 +1,5 @@
-use super::{abi, error};
+#![allow(dead_code)]
+
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
@@ -7,9 +8,10 @@ use crate::os::raw::{c_int, c_short};
 use crate::os::solid::ffi::OsStrExt;
 use crate::path::{Path, PathBuf};
 use crate::sync::Arc;
+pub use crate::sys::fs::common::exists;
+use crate::sys::pal::{abi, error};
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
-pub use crate::sys_common::fs::exists;
 use crate::sys_common::ignore_notfound;
 
 type CIntNotMinusOne = core::num::niche_types::NotAllOnes<c_int>;
diff --git a/library/std/src/sys/pal/uefi/fs.rs b/library/std/src/sys/fs/uefi.rs
index 45e93deffa3..45e93deffa3 100644
--- a/library/std/src/sys/pal/uefi/fs.rs
+++ b/library/std/src/sys/fs/uefi.rs
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/fs/unix.rs
index 3df460e38b7..914971934bf 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1,3 +1,5 @@
+#![allow(nonstandard_style)]
+#![allow(unsafe_op_in_unsafe_fn)]
 // miri has some special hacks here that make things unused.
 #![cfg_attr(miri, allow(unused))]
 
@@ -79,13 +81,13 @@ use crate::path::{Path, PathBuf};
 use crate::sync::Arc;
 use crate::sys::common::small_c_string::run_path_with_cstr;
 use crate::sys::fd::FileDesc;
+pub use crate::sys::fs::common::exists;
 use crate::sys::time::SystemTime;
 #[cfg(all(target_os = "linux", target_env = "gnu"))]
 use crate::sys::weak::syscall;
 #[cfg(target_os = "android")]
 use crate::sys::weak::weak;
 use crate::sys::{cvt, cvt_r};
-pub use crate::sys_common::fs::exists;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{mem, ptr};
 
@@ -699,6 +701,8 @@ impl Iterator for ReadDir {
         target_os = "hurd",
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        use crate::sys::os::{errno, set_errno};
+
         if self.end_of_stream {
             return None;
         }
@@ -710,7 +714,7 @@ impl Iterator for ReadDir {
                 // with unlimited or variable NAME_MAX. Many modern platforms guarantee
                 // thread safety for readdir() as long an individual DIR* is not accessed
                 // concurrently, which is sufficient for Rust.
-                super::os::set_errno(0);
+                set_errno(0);
                 let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
                     // We either encountered an error, or reached the end. Either way,
@@ -719,7 +723,7 @@ impl Iterator for ReadDir {
 
                     // To distinguish between errors and end-of-directory, we had to clear
                     // errno beforehand to check for an error now.
-                    return match super::os::errno() {
+                    return match errno() {
                         0 => None,
                         e => Some(Err(Error::from_raw_os_error(e))),
                     };
@@ -1505,7 +1509,7 @@ impl File {
                     self.as_raw_fd(),
                     (&raw const attrlist).cast::<libc::c_void>().cast_mut(),
                     buf.as_ptr().cast::<libc::c_void>().cast_mut(),
-                    num_times * mem::size_of::<libc::timespec>(),
+                    num_times * size_of::<libc::timespec>(),
                     0
                 ) })?;
                 Ok(())
@@ -1660,7 +1664,7 @@ impl fmt::Debug for File {
         fn get_path(fd: c_int) -> Option<PathBuf> {
             let info = Box::<libc::kinfo_file>::new_zeroed();
             let mut info = unsafe { info.assume_init() };
-            info.kf_structsize = mem::size_of::<libc::kinfo_file>() as libc::c_int;
+            info.kf_structsize = size_of::<libc::kinfo_file>() as libc::c_int;
             let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
             if n == -1 {
                 return None;
@@ -1932,7 +1936,7 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
 
 fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> {
     use crate::fs::File;
-    use crate::sys_common::fs::NOT_FILE_ERROR;
+    use crate::sys::fs::common::NOT_FILE_ERROR;
 
     let reader = File::open(from)?;
     let metadata = reader.metadata()?;
@@ -2151,7 +2155,7 @@ pub use remove_dir_impl::remove_dir_all;
     miri
 ))]
 mod remove_dir_impl {
-    pub use crate::sys_common::fs::remove_dir_all;
+    pub use crate::sys::fs::common::remove_dir_all;
 }
 
 // Modern implementation using openat(), unlinkat() and fdopendir()
diff --git a/library/std/src/sys/pal/unix/fs/tests.rs b/library/std/src/sys/fs/unix/tests.rs
index 71be3472148..8875a318db7 100644
--- a/library/std/src/sys/pal/unix/fs/tests.rs
+++ b/library/std/src/sys/fs/unix/tests.rs
@@ -1,4 +1,4 @@
-use crate::sys::pal::unix::fs::FilePermissions;
+use crate::sys::fs::FilePermissions;
 
 #[test]
 fn test_debug_permissions() {
diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/fs/unsupported.rs
index 45e93deffa3..45e93deffa3 100644
--- a/library/std/src/sys/pal/unsupported/fs.rs
+++ b/library/std/src/sys/fs/unsupported.rs
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/fs/wasi.rs
index 39978346d73..773040571bc 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/fs/wasi.rs
@@ -1,6 +1,3 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-
-use super::fd::WasiFd;
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem::{self, ManuallyDrop};
@@ -10,9 +7,10 @@ use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd
 use crate::path::{Path, PathBuf};
 use crate::sync::Arc;
 use crate::sys::common::small_c_string::run_path_with_cstr;
+use crate::sys::fd::WasiFd;
+pub use crate::sys::fs::common::exists;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
-pub use crate::sys_common::fs::exists;
 use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound};
 use crate::{fmt, iter, ptr};
 
@@ -209,7 +207,7 @@ impl Iterator for ReadDir {
             }
             ReadDirState::ProcessEntry { buf, next_read_offset, offset } => {
                 let contents = &buf[*offset..];
-                const DIRENT_SIZE: usize = crate::mem::size_of::<wasi::Dirent>();
+                const DIRENT_SIZE: usize = size_of::<wasi::Dirent>();
                 if contents.len() >= DIRENT_SIZE {
                     let (dirent, data) = contents.split_at(DIRENT_SIZE);
                     let dirent =
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/fs/windows.rs
index 623a7d89ba5..362e64abf1a 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -1,15 +1,17 @@
-use super::api::{self, WinError, set_file_information_by_handle};
-use super::{IoResult, to_u16s};
-use crate::alloc::{alloc, handle_alloc_error};
+#![allow(nonstandard_style)]
+
+use crate::alloc::{Layout, alloc, dealloc};
 use crate::borrow::Cow;
 use crate::ffi::{OsStr, OsString, c_void};
 use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
-use crate::mem::{self, MaybeUninit};
+use crate::mem::{self, MaybeUninit, offset_of};
 use crate::os::windows::io::{AsHandle, BorrowedHandle};
 use crate::os::windows::prelude::*;
 use crate::path::{Path, PathBuf};
 use crate::sync::Arc;
 use crate::sys::handle::Handle;
+use crate::sys::pal::api::{self, WinError, set_file_information_by_handle};
+use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul};
 use crate::sys::path::maybe_verbatim;
 use crate::sys::time::SystemTime;
 use crate::sys::{Align8, c, cvt};
@@ -167,7 +169,7 @@ impl DirEntry {
     }
 
     pub fn file_name(&self) -> OsString {
-        let filename = super::truncate_utf16_at_nul(&self.data.cFileName);
+        let filename = truncate_utf16_at_nul(&self.data.cFileName);
         OsString::from_wide(filename)
     }
 
@@ -477,7 +479,7 @@ impl File {
                     self.handle.as_raw_handle(),
                     c::FileAttributeTagInfo,
                     (&raw mut attr_tag).cast(),
-                    mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
+                    size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
                 ))?;
                 if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
                     reparse_tag = attr_tag.ReparseTag;
@@ -504,7 +506,7 @@ impl File {
     pub fn file_attr(&self) -> io::Result<FileAttr> {
         unsafe {
             let mut info: c::FILE_BASIC_INFO = mem::zeroed();
-            let size = mem::size_of_val(&info);
+            let size = size_of_val(&info);
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
@@ -536,7 +538,7 @@ impl File {
                 file_index: None,
             };
             let mut info: c::FILE_STANDARD_INFO = mem::zeroed();
-            let size = mem::size_of_val(&info);
+            let size = size_of_val(&info);
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileStandardInfo,
@@ -551,7 +553,7 @@ impl File {
                     self.handle.as_raw_handle(),
                     c::FileAttributeTagInfo,
                     (&raw mut attr_tag).cast(),
-                    mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
+                    size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
                 ))?;
                 if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
                     attr.reparse_tag = attr_tag.ReparseTag;
@@ -649,7 +651,7 @@ impl File {
                     ptr::null_mut(),
                 )
             })?;
-            const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
+            const _: () = assert!(align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
             Ok((bytes, space.0.as_mut_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
         }
     }
@@ -695,7 +697,7 @@ impl File {
                 // Turn `\??\` into `\\?\` (a verbatim path).
                 subst[1] = b'\\' as u16;
                 // Attempt to convert to a more user-friendly path.
-                let user = super::args::from_wide_to_user_path(
+                let user = crate::sys::args::from_wide_to_user_path(
                     subst.iter().copied().chain([0]).collect(),
                 )?;
                 Ok(PathBuf::from(OsString::from_wide(user.strip_suffix(&[0]).unwrap_or(&user))))
@@ -753,7 +755,7 @@ impl File {
     fn basic_info(&self) -> io::Result<c::FILE_BASIC_INFO> {
         unsafe {
             let mut info: c::FILE_BASIC_INFO = mem::zeroed();
-            let size = mem::size_of_val(&info);
+            let size = size_of_val(&info);
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
@@ -886,7 +888,6 @@ impl<'a> DirBuffIter<'a> {
 impl<'a> Iterator for DirBuffIter<'a> {
     type Item = (Cow<'a, [u16]>, bool);
     fn next(&mut self) -> Option<Self::Item> {
-        use crate::mem::size_of;
         let buffer = &self.buffer?[self.cursor..];
 
         // Get the name and next entry from the buffer.
@@ -1242,141 +1243,72 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
     let old = maybe_verbatim(old)?;
     let new = maybe_verbatim(new)?;
 
-    let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap();
-
-    // The last field of FILE_RENAME_INFO, the file name, is unsized,
-    // and FILE_RENAME_INFO has two padding bytes.
-    // Therefore we need to make sure to not allocate less than
-    // size_of::<c::FILE_RENAME_INFO>() bytes, which would be the case with
-    // 0 or 1 character paths + a null byte.
-    let struct_size = mem::size_of::<c::FILE_RENAME_INFO>()
-        .max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * mem::size_of::<u16>());
-
-    let struct_size: u32 = struct_size.try_into().unwrap();
-
-    let create_file = |extra_access, extra_flags| {
-        let handle = unsafe {
-            HandleOrInvalid::from_raw_handle(c::CreateFileW(
-                old.as_ptr(),
-                c::SYNCHRONIZE | c::DELETE | extra_access,
-                c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
-                ptr::null(),
-                c::OPEN_EXISTING,
-                c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags,
-                ptr::null_mut(),
-            ))
-        };
-
-        OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error())
-    };
-
-    // The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly.
-    // If `old` refers to a mount point, we move it instead of the target.
-    let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) {
-        Ok(handle) => {
-            let mut file_attribute_tag_info: MaybeUninit<c::FILE_ATTRIBUTE_TAG_INFO> =
-                MaybeUninit::uninit();
-
-            let result = unsafe {
-                cvt(c::GetFileInformationByHandleEx(
-                    handle.as_raw_handle(),
-                    c::FileAttributeTagInfo,
-                    file_attribute_tag_info.as_mut_ptr().cast(),
-                    mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
-                ))
+    if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 {
+        let err = api::get_last_error();
+        // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move
+        // the file while ignoring the readonly attribute.
+        // This is accomplished by calling `SetFileInformationByHandle` with `FileRenameInfoEx`.
+        if err == WinError::ACCESS_DENIED {
+            let mut opts = OpenOptions::new();
+            opts.access_mode(c::DELETE);
+            opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
+            let Ok(f) = File::open_native(&old, &opts) else { return Err(err).io_result() };
+
+            // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
+            // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
+            let Ok(new_len_without_nul_in_bytes): Result<u32, _> = ((new.len() - 1) * 2).try_into()
+            else {
+                return Err(err).io_result();
             };
-
-            if let Err(err) = result {
-                if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _)
-                    || err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _)
-                {
-                    // `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes.
-                    // Since we know we passed the correct arguments, this means the underlying driver didn't understand our request;
-                    // `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior.
-                    None
-                } else {
-                    Some(Err(err))
-                }
-            } else {
-                // SAFETY: The struct has been initialized by GetFileInformationByHandleEx
-                let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() };
-                let file_type = FileType::new(
-                    file_attribute_tag_info.FileAttributes,
-                    file_attribute_tag_info.ReparseTag,
-                );
-
-                if file_type.is_symlink() {
-                    // The file is a mount point, junction point or symlink so
-                    // don't reopen the file so that the link gets renamed.
-                    Some(Ok(handle))
-                } else {
-                    // Otherwise reopen the file without inhibiting reparse point behavior.
-                    None
+            let offset: u32 = offset_of!(c::FILE_RENAME_INFO, FileName).try_into().unwrap();
+            let struct_size = offset + new_len_without_nul_in_bytes + 2;
+            let layout =
+                Layout::from_size_align(struct_size as usize, align_of::<c::FILE_RENAME_INFO>())
+                    .unwrap();
+
+            // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename.
+            let file_rename_info;
+            unsafe {
+                file_rename_info = alloc(layout).cast::<c::FILE_RENAME_INFO>();
+                if file_rename_info.is_null() {
+                    return Err(io::ErrorKind::OutOfMemory.into());
                 }
-            }
-        }
-        // The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it.
-        Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None,
-        Err(err) => Some(Err(err)),
-    }
-    .unwrap_or_else(|| create_file(0, 0))?;
-
-    let layout = core::alloc::Layout::from_size_align(
-        struct_size as _,
-        mem::align_of::<c::FILE_RENAME_INFO>(),
-    )
-    .unwrap();
-
-    let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO;
-
-    if file_rename_info.is_null() {
-        handle_alloc_error(layout);
-    }
 
-    // SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator.
-    let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) };
+                (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 {
+                    Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS
+                        | c::FILE_RENAME_FLAG_POSIX_SEMANTICS,
+                });
 
-    // SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename.
-    unsafe {
-        (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 {
-            Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS,
-        });
-
-        (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut());
-        (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes);
-
-        new.as_ptr()
-            .copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len());
-    }
-
-    // We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`.
-    let result = unsafe {
-        cvt(c::SetFileInformationByHandle(
-            handle.as_raw_handle(),
-            c::FileRenameInfoEx,
-            (&raw const *file_rename_info).cast::<c_void>(),
-            struct_size,
-        ))
-    };
+                (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut());
+                // Don't include the NULL in the size
+                (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes);
 
-    if let Err(err) = result {
-        if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) {
-            // FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo.
-            file_rename_info.Anonymous.ReplaceIfExists = true;
+                new.as_ptr().copy_to_nonoverlapping(
+                    (&raw mut (*file_rename_info).FileName).cast::<u16>(),
+                    new.len(),
+                );
+            }
 
-            cvt(unsafe {
+            let result = unsafe {
                 c::SetFileInformationByHandle(
-                    handle.as_raw_handle(),
-                    c::FileRenameInfo,
-                    (&raw const *file_rename_info).cast::<c_void>(),
+                    f.as_raw_handle(),
+                    c::FileRenameInfoEx,
+                    file_rename_info.cast::<c_void>(),
                     struct_size,
                 )
-            })?;
+            };
+            unsafe { dealloc(file_rename_info.cast::<u8>(), layout) };
+            if result == 0 {
+                if api::get_last_error() == WinError::DIR_NOT_EMPTY {
+                    return Err(WinError::DIR_NOT_EMPTY).io_result();
+                } else {
+                    return Err(err).io_result();
+                }
+            }
         } else {
-            return Err(err);
+            return Err(err).io_result();
         }
     }
-
     Ok(())
 }
 
@@ -1562,7 +1494,7 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
 }
 
 fn get_path(f: &File) -> io::Result<PathBuf> {
-    super::fill_utf16_buf(
+    fill_utf16_buf(
         |buf, sz| unsafe {
             c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS)
         },
diff --git a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs
index 9416049da78..f51eced8416 100644
--- a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs
+++ b/library/std/src/sys/fs/windows/remove_dir_all.rs
@@ -33,7 +33,7 @@ use core::sync::atomic::{AtomicU32, Ordering};
 
 use super::{AsRawHandle, DirBuff, File, FromRawHandle};
 use crate::sys::c;
-use crate::sys::pal::windows::api::WinError;
+use crate::sys::pal::api::WinError;
 use crate::thread;
 
 // The maximum number of times to spin when waiting for deletes to complete.
diff --git a/library/std/src/sys/io/is_terminal/windows.rs b/library/std/src/sys/io/is_terminal/windows.rs
index 3ec18fb47b9..b0c718d71f9 100644
--- a/library/std/src/sys/io/is_terminal/windows.rs
+++ b/library/std/src/sys/io/is_terminal/windows.rs
@@ -1,5 +1,4 @@
 use crate::ffi::c_void;
-use crate::mem::size_of;
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
 use crate::sys::c;
 
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 1032fcba5e2..09677b9d642 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -12,11 +12,13 @@ pub mod anonymous_pipe;
 pub mod backtrace;
 pub mod cmath;
 pub mod exit_guard;
+pub mod fs;
 pub mod io;
 pub mod net;
 pub mod os_str;
 pub mod path;
 pub mod random;
+pub mod stdio;
 pub mod sync;
 pub mod thread_local;
 
diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket.rs
index ddd74b42615..e154cf039ca 100644
--- a/library/std/src/sys/net/connection/socket.rs
+++ b/library/std/src/sys/net/connection/socket.rs
@@ -154,11 +154,11 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) {
     match addr {
         SocketAddr::V4(a) => {
             let sockaddr = SocketAddrCRepr { v4: socket_addr_v4_to_c(a) };
-            (sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t)
+            (sockaddr, size_of::<c::sockaddr_in>() as c::socklen_t)
         }
         SocketAddr::V6(a) => {
             let sockaddr = SocketAddrCRepr { v6: socket_addr_v6_to_c(a) };
-            (sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t)
+            (sockaddr, size_of::<c::sockaddr_in6>() as c::socklen_t)
         }
     }
 }
@@ -169,13 +169,13 @@ unsafe fn socket_addr_from_c(
 ) -> io::Result<SocketAddr> {
     match (*storage).ss_family as c_int {
         c::AF_INET => {
-            assert!(len >= mem::size_of::<c::sockaddr_in>());
+            assert!(len >= size_of::<c::sockaddr_in>());
             Ok(SocketAddr::V4(socket_addr_v4_from_c(unsafe {
                 *(storage as *const _ as *const c::sockaddr_in)
             })))
         }
         c::AF_INET6 => {
-            assert!(len >= mem::size_of::<c::sockaddr_in6>());
+            assert!(len >= size_of::<c::sockaddr_in6>());
             Ok(SocketAddr::V6(socket_addr_v6_from_c(unsafe {
                 *(storage as *const _ as *const c::sockaddr_in6)
             })))
@@ -200,7 +200,7 @@ pub fn setsockopt<T>(
             level,
             option_name,
             (&raw const option_value) as *const _,
-            mem::size_of::<T>() as c::socklen_t,
+            size_of::<T>() as c::socklen_t,
         ))?;
         Ok(())
     }
@@ -209,7 +209,7 @@ pub fn setsockopt<T>(
 pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> {
     unsafe {
         let mut option_value: T = mem::zeroed();
-        let mut option_len = mem::size_of::<T>() as c::socklen_t;
+        let mut option_len = size_of::<T>() as c::socklen_t;
         cvt(c::getsockopt(
             sock.as_raw(),
             level,
@@ -227,7 +227,7 @@ where
 {
     unsafe {
         let mut storage: c::sockaddr_storage = mem::zeroed();
-        let mut len = mem::size_of_val(&storage) as c::socklen_t;
+        let mut len = size_of_val(&storage) as c::socklen_t;
         cvt(f((&raw mut storage) as *mut _, &mut len))?;
         socket_addr_from_c(&storage, len as usize)
     }
@@ -561,7 +561,7 @@ impl TcpListener {
         // so we don't need to zero it here.
         // reference: https://linux.die.net/man/2/accept4
         let mut storage: mem::MaybeUninit<c::sockaddr_storage> = mem::MaybeUninit::uninit();
-        let mut len = mem::size_of_val(&storage) as c::socklen_t;
+        let mut len = size_of_val(&storage) as c::socklen_t;
         let sock = self.inner.accept(storage.as_mut_ptr() as *mut _, &mut len)?;
         let addr = unsafe { socket_addr_from_c(storage.as_ptr(), len as usize)? };
         Ok((TcpStream { inner: sock }, addr))
diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs
index e393342ced9..f49821657d9 100644
--- a/library/std/src/sys/net/connection/socket/hermit.rs
+++ b/library/std/src/sys/net/connection/socket/hermit.rs
@@ -183,7 +183,7 @@ impl Socket {
 
     fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
         let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
-        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+        let mut addrlen = size_of_val(&storage) as netc::socklen_t;
 
         let n = cvt(unsafe {
             netc::recvfrom(
diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs
index 906bef267b6..94bb605c100 100644
--- a/library/std/src/sys/net/connection/socket/solid.rs
+++ b/library/std/src/sys/net/connection/socket/solid.rs
@@ -244,7 +244,7 @@ impl Socket {
         flags: c_int,
     ) -> io::Result<(usize, SocketAddr)> {
         let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
-        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+        let mut addrlen = size_of_val(&storage) as netc::socklen_t;
 
         let n = cvt(unsafe {
             netc::recvfrom(
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index 29fb47ddca3..e633cf772c5 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -326,7 +326,7 @@ impl Socket {
         // so we don't need to zero it here.
         // reference: https://linux.die.net/man/2/recvfrom
         let mut storage: mem::MaybeUninit<libc::sockaddr_storage> = mem::MaybeUninit::uninit();
-        let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
+        let mut addrlen = size_of_val(&storage) as libc::socklen_t;
 
         let n = cvt(unsafe {
             libc::recvfrom(
diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs
index c5034e73dd7..73c25831872 100644
--- a/library/std/src/sys/net/connection/socket/wasip2.rs
+++ b/library/std/src/sys/net/connection/socket/wasip2.rs
@@ -211,7 +211,7 @@ impl Socket {
         flags: c_int,
     ) -> io::Result<(usize, SocketAddr)> {
         let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
-        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+        let mut addrlen = size_of_val(&storage) as netc::socklen_t;
 
         let n = cvt(unsafe {
             netc::recvfrom(
diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs
index 428f142dabe..ce975bb2289 100644
--- a/library/std/src/sys/net/connection/socket/windows.rs
+++ b/library/std/src/sys/net/connection/socket/windows.rs
@@ -381,7 +381,7 @@ impl Socket {
         flags: c_int,
     ) -> io::Result<(usize, SocketAddr)> {
         let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE>() };
-        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+        let mut addrlen = size_of_val(&storage) as netc::socklen_t;
         let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
 
         // On unix when a socket is shut down all further reads return 0, so we
@@ -514,13 +514,13 @@ impl Socket {
 
     // This is used by sys_common code to abstract over Windows and Unix.
     pub fn as_raw(&self) -> c::SOCKET {
-        debug_assert_eq!(mem::size_of::<c::SOCKET>(), mem::size_of::<RawSocket>());
-        debug_assert_eq!(mem::align_of::<c::SOCKET>(), mem::align_of::<RawSocket>());
+        debug_assert_eq!(size_of::<c::SOCKET>(), size_of::<RawSocket>());
+        debug_assert_eq!(align_of::<c::SOCKET>(), align_of::<RawSocket>());
         self.as_inner().as_raw_socket() as c::SOCKET
     }
     pub unsafe fn from_raw(raw: c::SOCKET) -> Self {
-        debug_assert_eq!(mem::size_of::<c::SOCKET>(), mem::size_of::<RawSocket>());
-        debug_assert_eq!(mem::align_of::<c::SOCKET>(), mem::align_of::<RawSocket>());
+        debug_assert_eq!(size_of::<c::SOCKET>(), size_of::<RawSocket>());
+        debug_assert_eq!(align_of::<c::SOCKET>(), align_of::<RawSocket>());
         unsafe { Self::from_raw_socket(raw as RawSocket) }
     }
 }
diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs
index f35970bc321..c112c04ce94 100644
--- a/library/std/src/sys/net/connection/xous/udp.rs
+++ b/library/std/src/sys/net/connection/xous/udp.rs
@@ -244,7 +244,7 @@ impl UdpSocket {
         // let buf = unsafe {
         //     xous::MemoryRange::new(
         //         &mut tx_req as *mut SendData as usize,
-        //         core::mem::size_of::<SendData>(),
+        //         size_of::<SendData>(),
         //     )
         //     .unwrap()
         // };
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 1d337694944..dfff2d3e5d3 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -140,6 +140,11 @@ impl Buf {
     }
 
     #[inline]
+    pub fn push_str(&mut self, s: &str) {
+        self.inner.extend_from_slice(s.as_bytes());
+    }
+
+    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional)
     }
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index 8acec6f949f..a32f5d40f6a 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -117,6 +117,11 @@ impl Buf {
     }
 
     #[inline]
+    pub fn push_str(&mut self, s: &str) {
+        self.inner.push_str(s);
+    }
+
+    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional)
     }
diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs
index 79fc13bd4a8..edd984d920a 100644
--- a/library/std/src/sys/pal/hermit/fd.rs
+++ b/library/std/src/sys/pal/hermit/fd.rs
@@ -2,8 +2,8 @@
 
 use super::hermit_abi;
 use crate::cmp;
-use crate::io::{self, IoSlice, IoSliceMut, Read};
-use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd, *};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom};
+use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::{cvt, unsupported};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
@@ -23,6 +23,21 @@ impl FileDesc {
         Ok(result as usize)
     }
 
+    pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        // SAFETY: The `read` syscall does not read from the buffer, so it is
+        // safe to use `&mut [MaybeUninit<u8>]`.
+        let result = cvt(unsafe {
+            hermit_abi::read(
+                self.fd.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut u8,
+                buf.capacity(),
+            )
+        })?;
+        // SAFETY: Exactly `result` bytes have been filled.
+        unsafe { buf.advance_unchecked(result as usize) };
+        Ok(())
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             hermit_abi::readv(
@@ -66,9 +81,26 @@ impl FileDesc {
         true
     }
 
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        let (whence, pos) = match pos {
+            // Casting to `i64` is fine, too large values will end up as
+            // negative which will cause an error in `lseek`.
+            SeekFrom::Start(off) => (hermit_abi::SEEK_SET, off as i64),
+            SeekFrom::End(off) => (hermit_abi::SEEK_END, off),
+            SeekFrom::Current(off) => (hermit_abi::SEEK_CUR, off),
+        };
+        let n = cvt(unsafe { hermit_abi::lseek(self.as_raw_fd(), pos as isize, whence) })?;
+        Ok(n as u64)
+    }
+
+    pub fn tell(&self) -> io::Result<u64> {
+        self.seek(SeekFrom::Current(0))
+    }
+
     pub fn duplicate(&self) -> io::Result<FileDesc> {
         self.duplicate_path(&[])
     }
+
     pub fn duplicate_path(&self, _path: &[u8]) -> io::Result<FileDesc> {
         unsupported()
     }
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 21cbac643bb..608245bd430 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -21,14 +21,12 @@ use crate::os::raw::c_char;
 pub mod args;
 pub mod env;
 pub mod fd;
-pub mod fs;
 pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs
deleted file mode 100644
index 3ea00f5cc5e..00000000000
--- a/library/std/src/sys/pal/hermit/stdio.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-use super::hermit_abi;
-use crate::io;
-use crate::io::{IoSlice, IoSliceMut};
-use crate::mem::ManuallyDrop;
-use crate::os::hermit::io::FromRawFd;
-use crate::sys::fd::FileDesc;
-
-pub struct Stdin;
-pub struct Stdout;
-pub struct Stderr;
-
-impl Stdin {
-    pub const fn new() -> Stdin {
-        Stdin
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read(buf) }
-    }
-
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        unsafe {
-            ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read_vectored(bufs)
-        }
-    }
-
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        true
-    }
-}
-
-impl Stdout {
-    pub const fn new() -> Stdout {
-        Stdout
-    }
-}
-
-impl io::Write for Stdout {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write(buf) }
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsafe {
-            ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write_vectored(bufs)
-        }
-    }
-
-    #[inline]
-    fn is_write_vectored(&self) -> bool {
-        true
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl Stderr {
-    pub const fn new() -> Stderr {
-        Stderr
-    }
-}
-
-impl io::Write for Stderr {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write(buf) }
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsafe {
-            ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write_vectored(bufs)
-        }
-    }
-
-    #[inline]
-    fn is_write_vectored(&self) -> bool {
-        true
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-pub const STDIN_BUF_SIZE: usize = 128;
-
-pub fn is_ebadf(err: &io::Error) -> bool {
-    err.raw_os_error() == Some(hermit_abi::EBADF)
-}
-
-pub fn panic_output() -> Option<impl io::Write> {
-    Some(Stderr::new())
-}
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 04095e1a7cf..d1481f827e1 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -80,7 +80,7 @@ const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
 // there's no single value for `JOINING`
 
 // 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs.
-pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::<usize>();
+pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * size_of::<usize>();
 
 impl Thread {
     /// # Safety
diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs
index 90981bd6a6a..2c805a4d0af 100644
--- a/library/std/src/sys/pal/sgx/abi/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/mod.rs
@@ -6,7 +6,7 @@ use core::sync::atomic::{AtomicUsize, Ordering};
 use crate::io::Write;
 
 // runtime features
-pub(super) mod panic;
+pub mod panic;
 mod reloc;
 
 // library features
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
index 5069ab82ccc..301e3299c05 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
@@ -63,7 +63,7 @@ unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
 /// A type that can be represented in memory as one or more `UserSafeSized`s.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub unsafe trait UserSafe {
-    /// Equivalent to `mem::align_of::<Self>`.
+    /// Equivalent to `align_of::<Self>`.
     fn align_of() -> usize;
 
     /// Constructs a pointer to `Self` given a memory range in user space.
@@ -120,7 +120,7 @@ pub unsafe trait UserSafe {
         let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) };
 
         assert!(is_aligned(ptr as *const u8));
-        assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
+        assert!(is_user_range(ptr as _, size_of_val(unsafe { &*ptr })));
         assert!(!ptr.is_null());
     }
 }
@@ -128,11 +128,11 @@ pub unsafe trait UserSafe {
 #[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl<T: UserSafeSized> UserSafe for T {
     fn align_of() -> usize {
-        mem::align_of::<T>()
+        align_of::<T>()
     }
 
     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
-        assert_eq!(size, mem::size_of::<T>());
+        assert_eq!(size, size_of::<T>());
         ptr as _
     }
 }
@@ -140,7 +140,7 @@ unsafe impl<T: UserSafeSized> UserSafe for T {
 #[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl<T: UserSafeSized> UserSafe for [T] {
     fn align_of() -> usize {
-        mem::align_of::<T>()
+        align_of::<T>()
     }
 
     /// # Safety
@@ -155,7 +155,7 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
     ///
     /// * the element size is not a factor of the size
     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
-        let elem_size = mem::size_of::<T>();
+        let elem_size = size_of::<T>();
         assert_eq!(size % elem_size, 0);
         let len = size / elem_size;
         // SAFETY: The caller must uphold the safety contract for `from_raw_sized_unchecked`
@@ -239,7 +239,7 @@ where
     /// Copies `val` into freshly allocated space in user memory.
     pub fn new_from_enclave(val: &T) -> Self {
         unsafe {
-            let mut user = Self::new_uninit_bytes(mem::size_of_val(val));
+            let mut user = Self::new_uninit_bytes(size_of_val(val));
             user.copy_from_enclave(val);
             user
         }
@@ -277,7 +277,7 @@ where
 {
     /// Allocates space for `T` in user memory.
     pub fn uninitialized() -> Self {
-        Self::new_uninit_bytes(mem::size_of::<T>())
+        Self::new_uninit_bytes(size_of::<T>())
     }
 }
 
@@ -288,7 +288,7 @@ where
 {
     /// Allocates space for a `[T]` of `n` elements in user memory.
     pub fn uninitialized(n: usize) -> Self {
-        Self::new_uninit_bytes(n * mem::size_of::<T>())
+        Self::new_uninit_bytes(n * size_of::<T>())
     }
 
     /// Creates an owned `User<[T]>` from a raw thin pointer and a slice length.
@@ -306,9 +306,7 @@ where
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
-        User(unsafe {
-            NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()))
-        })
+        User(unsafe { NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * size_of::<T>())) })
     }
 }
 
@@ -326,7 +324,7 @@ where
 // `<*const u8>::align_offset` aren't _guaranteed_ to compute the largest
 // possible middle region, and as such can't be used.
 fn u64_align_to_guaranteed(ptr: *const u8, mut len: usize) -> (usize, usize, usize) {
-    const QWORD_SIZE: usize = mem::size_of::<u64>();
+    const QWORD_SIZE: usize = size_of::<u64>();
 
     let offset = ptr as usize % QWORD_SIZE;
 
@@ -532,11 +530,11 @@ where
     /// the source. This can happen for dynamically-sized types such as slices.
     pub fn copy_from_enclave(&mut self, val: &T) {
         unsafe {
-            assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get()));
+            assert_eq!(size_of_val(val), size_of_val(&*self.0.get()));
             copy_to_userspace(
                 val as *const T as *const u8,
                 self.0.get() as *mut T as *mut u8,
-                mem::size_of_val(val),
+                size_of_val(val),
             );
         }
     }
@@ -548,11 +546,11 @@ where
     /// the source. This can happen for dynamically-sized types such as slices.
     pub fn copy_to_enclave(&self, dest: &mut T) {
         unsafe {
-            assert_eq!(mem::size_of_val(dest), mem::size_of_val(&*self.0.get()));
+            assert_eq!(size_of_val(dest), size_of_val(&*self.0.get()));
             copy_from_userspace(
                 self.0.get() as *const T as *const u8,
                 dest as *mut T as *mut u8,
-                mem::size_of_val(dest),
+                size_of_val(dest),
             );
         }
     }
@@ -577,7 +575,7 @@ where
     pub fn to_enclave(&self) -> T {
         unsafe {
             let mut data = mem::MaybeUninit::uninit();
-            copy_from_userspace(self.0.get() as _, data.as_mut_ptr() as _, mem::size_of::<T>());
+            copy_from_userspace(self.0.get() as _, data.as_mut_ptr() as _, size_of::<T>());
             data.assume_init()
         }
     }
@@ -602,9 +600,7 @@ where
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
         // SAFETY: The caller must uphold the safety contract for `from_raw_parts`.
-        unsafe {
-            &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
-        }
+        unsafe { &*(<[T]>::from_raw_sized(ptr as _, len * size_of::<T>()).as_ptr() as *const Self) }
     }
 
     /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
@@ -624,7 +620,7 @@ where
     pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
         // SAFETY: The caller must uphold the safety contract for `from_raw_parts_mut`.
         unsafe {
-            &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
+            &mut *(<[T]>::from_raw_sized(ptr as _, len * size_of::<T>()).as_ptr() as *mut Self)
         }
     }
 
@@ -744,7 +740,7 @@ where
     fn drop(&mut self) {
         unsafe {
             let ptr = (*self.0.as_ptr()).0.get();
-            super::free(ptr as _, mem::size_of_val(&mut *ptr), T::align_of());
+            super::free(ptr as _, size_of_val(&mut *ptr), T::align_of());
         }
     }
 }
diff --git a/library/std/src/sys/pal/sgx/libunwind_integration.rs b/library/std/src/sys/pal/sgx/libunwind_integration.rs
index 6d0d78d1eb9..b5419ad05de 100644
--- a/library/std/src/sys/pal/sgx/libunwind_integration.rs
+++ b/library/std/src/sys/pal/sgx/libunwind_integration.rs
@@ -4,6 +4,7 @@
 #![cfg(not(test))]
 
 use crate::sys::sync::RwLock;
+use crate::{slice, str};
 
 // Verify that the byte pattern libunwind uses to initialize an RwLock is
 // equivalent to the value of RwLock::new(). If the value changes,
@@ -44,3 +45,14 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
     unsafe { (*p).write_unlock() };
     return 0;
 }
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
+    if s < 0 {
+        return;
+    }
+    let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
+    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
+        eprint!("{s}");
+    }
+}
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 37ca6b08c95..bb419c2530e 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -12,15 +12,12 @@ pub mod abi;
 pub mod args;
 pub mod env;
 pub mod fd;
-#[path = "../unsupported/fs.rs"]
-pub mod fs;
 mod libunwind_integration;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod thread_parking;
 pub mod time;
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 06af7bfade0..e4a61fdcfe3 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -22,13 +22,11 @@ pub mod env;
 // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
 // `crate::sys::error`
 pub(crate) mod error;
-pub mod fs;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 pub use self::itron::{thread, thread_parking};
 pub mod time;
 
diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs
index 3f9bbb0b63c..c39d715c6a6 100644
--- a/library/std/src/sys/pal/solid/time.rs
+++ b/library/std/src/sys/pal/solid/time.rs
@@ -35,7 +35,7 @@ impl SystemTime {
         SystemTime(t)
     }
 
-    pub(super) fn from_time_t(t: abi::time_t) -> Self {
+    pub fn from_time_t(t: abi::time_t) -> Self {
         Self(t)
     }
 
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index 3632524157d..41b25121592 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -11,14 +11,11 @@ pub mod args;
 #[path = "../unsupported/env.rs"]
 pub mod env;
 //pub mod fd;
-#[path = "../unsupported/fs.rs"]
-pub mod fs;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 pub mod thread;
 #[allow(non_upper_case_globals)]
 #[path = "../unix/time.rs"]
diff --git a/library/std/src/sys/pal/uefi/args.rs b/library/std/src/sys/pal/uefi/args.rs
index bdf6f5a0c1c..0c29caf2db6 100644
--- a/library/std/src/sys/pal/uefi/args.rs
+++ b/library/std/src/sys/pal/uefi/args.rs
@@ -4,7 +4,6 @@ use super::helpers;
 use crate::env::current_exe;
 use crate::ffi::OsString;
 use crate::iter::Iterator;
-use crate::mem::size_of;
 use crate::{fmt, vec};
 
 pub struct Args {
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index cca2312c4f9..0a2a8f5ef67 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -15,7 +15,7 @@ use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell}
 use crate::ffi::{OsStr, OsString};
 use crate::io::{self, const_error};
 use crate::marker::PhantomData;
-use crate::mem::{MaybeUninit, size_of};
+use crate::mem::MaybeUninit;
 use crate::os::uefi::env::boot_services;
 use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
 use crate::os::uefi::{self};
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 6a03e240c6b..714dc392688 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -15,13 +15,11 @@
 
 pub mod args;
 pub mod env;
-pub mod fs;
 pub mod helpers;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index d4c09dc2ca0..1203d51e531 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -490,7 +490,7 @@ mod uefi_command_internal {
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
             let len = args.len();
-            let args_size: u32 = (len * crate::mem::size_of::<u16>()).try_into().unwrap();
+            let args_size: u32 = (len * size_of::<u16>()).try_into().unwrap();
             let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs
index 5eb36da922b..38658cc4e9a 100644
--- a/library/std/src/sys/pal/uefi/tests.rs
+++ b/library/std/src/sys/pal/uefi/tests.rs
@@ -16,7 +16,7 @@ fn align() {
             if *j <= 8 {
                 assert_eq!(align_size(i, *j), i);
             } else {
-                assert!(align_size(i, *j) > i + std::mem::size_of::<*mut ()>());
+                assert!(align_size(i, *j) > i + size_of::<*mut ()>());
             }
         }
     }
diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs
index d4551dd6a38..87ba13ca932 100644
--- a/library/std/src/sys/pal/unix/futex.rs
+++ b/library/std/src/sys/pal/unix/futex.rs
@@ -58,7 +58,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                         _clockid: libc::CLOCK_MONOTONIC as u32,
                     });
                     let umtx_timeout_ptr = umtx_timeout.as_ref().map_or(null(), |t| t as *const _);
-                    let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| crate::mem::size_of_val(t));
+                    let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| size_of_val(t));
                     libc::_umtx_op(
                         futex as *const AtomicU32 as *mut _,
                         libc::UMTX_OP_WAIT_UINT_PRIVATE,
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index c0b56d8d2b2..419abe732ac 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -9,7 +9,6 @@ pub mod weak;
 pub mod args;
 pub mod env;
 pub mod fd;
-pub mod fs;
 pub mod futex;
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub mod kernel_copy;
@@ -19,7 +18,6 @@ pub mod os;
 pub mod pipe;
 pub mod process;
 pub mod stack_overflow;
-pub mod stdio;
 pub mod sync;
 pub mod thread;
 pub mod thread_parking;
diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs
index 342818ac911..0ea9db211b3 100644
--- a/library/std/src/sys/pal/unix/process/process_common.rs
+++ b/library/std/src/sys/pal/unix/process/process_common.rs
@@ -43,10 +43,7 @@ cfg_if::cfg_if! {
 
         #[allow(dead_code)]
         pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
-            use crate::{
-                mem::{align_of, size_of},
-                slice,
-            };
+            use crate::slice;
             use libc::{c_ulong, sigset_t};
 
             // The implementations from bionic (android libc) type pun `sigset_t` as an
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
index 4ddc96356b9..05c9ace470e 100644
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
@@ -179,7 +179,7 @@ impl Process {
                 self.handle.raw(),
                 ZX_INFO_PROCESS,
                 (&raw mut proc_info) as *mut libc::c_void,
-                mem::size_of::<zx_info_process_t>(),
+                size_of::<zx_info_process_t>(),
                 &mut actual,
                 &mut avail,
             ))?;
@@ -216,7 +216,7 @@ impl Process {
                 self.handle.raw(),
                 ZX_INFO_PROCESS,
                 (&raw mut proc_info) as *mut libc::c_void,
-                mem::size_of::<zx_info_process_t>(),
+                size_of::<zx_info_process_t>(),
                 &mut actual,
                 &mut avail,
             ))?;
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index ddea445bb17..25d9e935332 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -814,7 +814,7 @@ impl Command {
 
             let fds: [c_int; 1] = [pidfd as RawFd];
 
-            const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>();
+            const SCM_MSG_LEN: usize = size_of::<[c_int; 1]>();
 
             #[repr(C)]
             union Cmsg {
@@ -833,7 +833,7 @@ impl Command {
 
             // only attach cmsg if we successfully acquired the pidfd
             if pidfd >= 0 {
-                msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
+                msg.msg_controllen = size_of_val(&cmsg.buf) as _;
                 msg.msg_control = (&raw mut cmsg.buf) as *mut _;
 
                 let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _);
@@ -865,7 +865,7 @@ impl Command {
         use crate::sys::cvt_r;
 
         unsafe {
-            const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>();
+            const SCM_MSG_LEN: usize = size_of::<[c_int; 1]>();
 
             #[repr(C)]
             union Cmsg {
@@ -880,7 +880,7 @@ impl Command {
 
             msg.msg_iov = (&raw mut iov) as *mut _;
             msg.msg_iovlen = 1;
-            msg.msg_controllen = mem::size_of::<Cmsg>() as _;
+            msg.msg_controllen = size_of::<Cmsg>() as _;
             msg.msg_control = (&raw mut cmsg) as *mut _;
 
             match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) {
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 43ece63457f..0ecccdc8812 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -426,7 +426,7 @@ mod imp {
             use crate::sys::weak::dlsym;
             dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
             let mut guard: usize = 0;
-            let mut size = mem::size_of_val(&guard);
+            let mut size = size_of_val(&guard);
             let oid = c"security.bsd.stack_guard_page";
             match sysctlbyname.get() {
                 Some(fcn) if unsafe {
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 3dedc8d1257..11f6998cac1 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -372,7 +372,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 quota = cgroups::quota().max(1);
                 let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
                 unsafe {
-                    if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 {
+                    if libc::sched_getaffinity(0, size_of::<libc::cpu_set_t>(), &mut set) == 0 {
                         let count = libc::CPU_COUNT(&set) as usize;
                         let count = count.min(quota);
 
@@ -412,7 +412,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                         libc::CPU_LEVEL_WHICH,
                         libc::CPU_WHICH_PID,
                         -1,
-                        mem::size_of::<libc::cpuset_t>(),
+                        size_of::<libc::cpuset_t>(),
                         &mut set,
                     ) == 0 {
                         let count = libc::CPU_COUNT(&set) as usize;
@@ -447,7 +447,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             }
 
             let mut cpus: libc::c_uint = 0;
-            let mut cpus_size = crate::mem::size_of_val(&cpus);
+            let mut cpus_size = size_of_val(&cpus);
 
             unsafe {
                 cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs
index 5a37598f438..7ec4787f1ea 100644
--- a/library/std/src/sys/pal/unix/weak.rs
+++ b/library/std/src/sys/pal/unix/weak.rs
@@ -123,7 +123,7 @@ impl<F> DlsymWeak<F> {
     // Cold because it should only happen during first-time initialization.
     #[cold]
     unsafe fn initialize(&self) -> Option<F> {
-        assert_eq!(mem::size_of::<F>(), mem::size_of::<*mut libc::c_void>());
+        assert_eq!(size_of::<F>(), size_of::<*mut libc::c_void>());
 
         let val = fetch(self.name);
         // This synchronizes with the acquire fence in `get`.
diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs
index b1aaeb1b4c8..bcea699f3b2 100644
--- a/library/std/src/sys/pal/unsupported/mod.rs
+++ b/library/std/src/sys/pal/unsupported/mod.rs
@@ -2,11 +2,9 @@
 
 pub mod args;
 pub mod env;
-pub mod fs;
 pub mod os;
 pub mod pipe;
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/wasi/fd.rs b/library/std/src/sys/pal/wasi/fd.rs
index 19b60157e2e..4b3dd1ce49e 100644
--- a/library/std/src/sys/pal/wasi/fd.rs
+++ b/library/std/src/sys/pal/wasi/fd.rs
@@ -14,8 +14,8 @@ pub struct WasiFd {
 }
 
 fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] {
-    assert_eq!(mem::size_of::<IoSliceMut<'_>>(), mem::size_of::<wasi::Iovec>());
-    assert_eq!(mem::align_of::<IoSliceMut<'_>>(), mem::align_of::<wasi::Iovec>());
+    assert_eq!(size_of::<IoSliceMut<'_>>(), size_of::<wasi::Iovec>());
+    assert_eq!(align_of::<IoSliceMut<'_>>(), align_of::<wasi::Iovec>());
     // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout.
     // We decorate our `IoSliceMut` with `repr(transparent)` (see `io.rs`), and
     // `crate::io::IoSliceMut` is a `repr(transparent)` wrapper around our type, so this is
@@ -24,8 +24,8 @@ fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] {
 }
 
 fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] {
-    assert_eq!(mem::size_of::<IoSlice<'_>>(), mem::size_of::<wasi::Ciovec>());
-    assert_eq!(mem::align_of::<IoSlice<'_>>(), mem::align_of::<wasi::Ciovec>());
+    assert_eq!(size_of::<IoSlice<'_>>(), size_of::<wasi::Ciovec>());
+    assert_eq!(align_of::<IoSlice<'_>>(), align_of::<wasi::Ciovec>());
     // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout.
     // We decorate our `IoSlice` with `repr(transparent)` (see `io.rs`), and
     // `crate::io::IoSlice` is a `repr(transparent)` wrapper around our type, so this is
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index f4588a60ea9..c89832857dd 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -16,7 +16,6 @@
 pub mod args;
 pub mod env;
 pub mod fd;
-pub mod fs;
 #[allow(unused)]
 #[path = "../wasm/atomics/futex.rs"]
 pub mod futex;
@@ -26,7 +25,6 @@ pub mod os;
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 0ae02369410..c85b03d4a89 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -13,16 +13,15 @@ cfg_if::cfg_if! {
         // Add a few symbols not in upstream `libc` just yet.
         mod libc {
             pub use crate::ffi;
-            pub use crate::mem;
             pub use libc::*;
 
             // defined in wasi-libc
             // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
             #[repr(C)]
             union pthread_attr_union {
-                __i: [ffi::c_int; if mem::size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
-                __vi: [ffi::c_int; if mem::size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
-                __s: [ffi::c_ulong; if mem::size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
+                __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
+                __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
+                __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
             }
 
             #[repr(C)]
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 72c9742b2e5..3008ba88753 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -12,8 +12,6 @@ pub mod args;
 pub mod env;
 #[path = "../wasi/fd.rs"]
 pub mod fd;
-#[path = "../wasi/fs.rs"]
-pub mod fs;
 #[allow(unused)]
 #[path = "../wasm/atomics/futex.rs"]
 pub mod futex;
@@ -24,8 +22,6 @@ pub mod os;
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-#[path = "../wasi/stdio.rs"]
-pub mod stdio;
 #[path = "../wasi/thread.rs"]
 pub mod thread;
 #[path = "../wasi/time.rs"]
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 32d59c4d0f7..175fe75357f 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -19,16 +19,12 @@
 #[path = "../unsupported/args.rs"]
 pub mod args;
 pub mod env;
-#[path = "../unsupported/fs.rs"]
-pub mod fs;
 #[path = "../unsupported/os.rs"]
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-#[path = "../unsupported/stdio.rs"]
-pub mod stdio;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs
index ebe207fde93..6b5f9aeace2 100644
--- a/library/std/src/sys/pal/windows/api.rs
+++ b/library/std/src/sys/pal/windows/api.rs
@@ -137,7 +137,7 @@ pub const fn to_utf16<const UTF16_LEN: usize>(s: &str) -> [u16; UTF16_LEN] {
 /// use frequent `as` casts. This is risky because they are too powerful.
 /// For example, the following will compile today:
 ///
-/// `std::mem::size_of::<u64> as u32`
+/// `size_of::<u64> as u32`
 ///
 /// Note that `size_of` is never actually called, instead a function pointer is
 /// converted to a `u32`. Clippy would warn about this but, alas, it's not run
@@ -147,7 +147,7 @@ const fn win32_size_of<T: Sized>() -> u32 {
     // Uses a trait to workaround restriction on using generic types in inner items.
     trait Win32SizeOf: Sized {
         const WIN32_SIZE_OF: u32 = {
-            let size = core::mem::size_of::<Self>();
+            let size = size_of::<Self>();
             assert!(size <= u32::MAX as usize);
             size as u32
         };
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 4fbdc839939..004cbee52f6 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -6,7 +6,7 @@
 #![allow(clippy::style)]
 
 use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void};
-use core::{mem, ptr};
+use core::ptr;
 
 mod windows_sys;
 pub use windows_sys::*;
@@ -39,7 +39,7 @@ pub fn nt_success(status: NTSTATUS) -> bool {
 
 impl UNICODE_STRING {
     pub fn from_ref(slice: &[u16]) -> Self {
-        let len = mem::size_of_val(slice);
+        let len = size_of_val(slice);
         Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
     }
 }
@@ -47,7 +47,7 @@ impl UNICODE_STRING {
 impl Default for OBJECT_ATTRIBUTES {
     fn default() -> Self {
         Self {
-            Length: mem::size_of::<Self>() as _,
+            Length: size_of::<Self>() as _,
             RootDirectory: ptr::null_mut(),
             ObjectName: ptr::null_mut(),
             Attributes: 0,
@@ -237,6 +237,17 @@ compat_fn_with_fallback! {
         STATUS_NOT_IMPLEMENTED
     }
     #[cfg(target_vendor = "uwp")]
+    pub fn NtOpenFile(
+        filehandle: *mut HANDLE,
+        desiredaccess: u32,
+        objectattributes: *const OBJECT_ATTRIBUTES,
+        iostatusblock: *mut IO_STATUS_BLOCK,
+        shareaccess: u32,
+        openoptions: u32
+    ) -> NTSTATUS {
+        STATUS_NOT_IMPLEMENTED
+    }
+    #[cfg(target_vendor = "uwp")]
     pub fn NtReadFile(
         filehandle: HANDLE,
         event: HANDLE,
diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs
index 38afb8c043b..aebf638239c 100644
--- a/library/std/src/sys/pal/windows/futex.rs
+++ b/library/std/src/sys/pal/windows/futex.rs
@@ -1,10 +1,10 @@
 use core::ffi::c_void;
+use core::ptr;
 use core::sync::atomic::{
     AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8,
     AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
 };
 use core::time::Duration;
-use core::{mem, ptr};
 
 use super::api::{self, WinError};
 use crate::sys::{c, dur2timeout};
@@ -61,7 +61,7 @@ pub fn wait_on_address<W: Waitable>(
 ) -> bool {
     unsafe {
         let addr = ptr::from_ref(address).cast::<c_void>();
-        let size = mem::size_of::<W>();
+        let size = size_of::<W>();
         let compare_addr = (&raw const compare).cast::<c_void>();
         let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE);
         c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 1eca346b76c..6eb68f3a3bc 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -17,14 +17,12 @@ pub mod api;
 pub mod args;
 pub mod c;
 pub mod env;
-pub mod fs;
 #[cfg(not(target_vendor = "win7"))]
 pub mod futex;
 pub mod handle;
 pub mod os;
 pub mod pipe;
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod time;
 cfg_if::cfg_if! {
@@ -37,7 +35,7 @@ cfg_if::cfg_if! {
 }
 
 /// Map a [`Result<T, WinError>`] to [`io::Result<T>`](crate::io::Result<T>).
-trait IoResult<T> {
+pub trait IoResult<T> {
     fn io_result(self) -> crate::io::Result<T>;
 }
 impl<T> IoResult<T> for Result<T, api::WinError> {
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index a8f6617c9dc..8521cf4162f 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -151,7 +151,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
         opts.write(ours_readable);
         opts.read(!ours_readable);
         opts.share_mode(0);
-        let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
+        let size = size_of::<c::SECURITY_ATTRIBUTES>();
         let mut sa = c::SECURITY_ATTRIBUTES {
             nLength: size as u32,
             lpSecurityDescriptor: ptr::null_mut(),
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index 6eff471f386..c57ff355d12 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -24,7 +24,7 @@ use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::{cvt, path, stdio};
 use crate::sys_common::IntoInner;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::{cmp, env, fmt, mem, ptr};
+use crate::{cmp, env, fmt, ptr};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
@@ -355,7 +355,7 @@ impl Command {
         let mut si_ex;
 
         if let Some(proc_thread_attribute_list) = proc_thread_attribute_list {
-            si.cb = mem::size_of::<c::STARTUPINFOEXW>() as u32;
+            si.cb = size_of::<c::STARTUPINFOEXW>() as u32;
             flags |= c::EXTENDED_STARTUPINFO_PRESENT;
 
             si_ex = c::STARTUPINFOEXW {
@@ -367,7 +367,7 @@ impl Command {
             };
             si_ptr = (&raw mut si_ex) as _;
         } else {
-            si.cb = mem::size_of::<c::STARTUPINFOW>() as u32;
+            si.cb = size_of::<c::STARTUPINFOW>() as u32;
             si_ptr = (&raw mut si) as _;
         }
 
@@ -599,7 +599,7 @@ impl Stdio {
             // permissions as well as the ability to be inherited to child
             // processes (as this is about to be inherited).
             Stdio::Null => {
-                let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
+                let size = size_of::<c::SECURITY_ATTRIBUTES>();
                 let mut sa = c::SECURITY_ATTRIBUTES {
                     nLength: size as u32,
                     lpSecurityDescriptor: ptr::null_mut(),
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index 1bd0e67f371..7d823012ad1 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -3,14 +3,11 @@
 pub mod args;
 #[path = "../unsupported/env.rs"]
 pub mod env;
-#[path = "../unsupported/fs.rs"]
-pub mod fs;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 054c867f90d..499e2787201 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -8,20 +8,17 @@
 //! will likely change over time.
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-const WORD_SIZE: usize = core::mem::size_of::<u32>();
+const WORD_SIZE: usize = size_of::<u32>();
 
 pub mod abi;
 #[path = "../zkvm/args.rs"]
 pub mod args;
 pub mod env;
-#[path = "../unsupported/fs.rs"]
-pub mod fs;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-pub mod stdio;
 #[path = "../unsupported/thread.rs"]
 pub mod thread;
 #[path = "../unsupported/time.rs"]
diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs
index 778d8686f02..ef5112ad74f 100644
--- a/library/std/src/sys/personality/dwarf/eh.rs
+++ b/library/std/src/sys/personality/dwarf/eh.rs
@@ -12,7 +12,7 @@
 #![allow(non_upper_case_globals)]
 #![allow(unused)]
 
-use core::{mem, ptr};
+use core::ptr;
 
 use super::DwarfReader;
 
@@ -245,8 +245,7 @@ unsafe fn read_encoded_pointer(
         DW_EH_PE_datarel => (*context.get_data_start)(),
         // aligned means the value is aligned to the size of a pointer
         DW_EH_PE_aligned => {
-            reader.ptr =
-                reader.ptr.with_addr(round_up(reader.ptr.addr(), mem::size_of::<*const u8>())?);
+            reader.ptr = reader.ptr.with_addr(round_up(reader.ptr.addr(), size_of::<*const u8>())?);
             core::ptr::null()
         }
         _ => return Err(()),
diff --git a/library/std/src/sys/personality/dwarf/mod.rs b/library/std/src/sys/personality/dwarf/mod.rs
index 5c52d96c4ca..2bc91951b49 100644
--- a/library/std/src/sys/personality/dwarf/mod.rs
+++ b/library/std/src/sys/personality/dwarf/mod.rs
@@ -12,8 +12,6 @@ mod tests;
 
 pub mod eh;
 
-use core::mem;
-
 pub struct DwarfReader {
     pub ptr: *const u8,
 }
@@ -29,7 +27,7 @@ impl DwarfReader {
     pub unsafe fn read<T: Copy>(&mut self) -> T {
         unsafe {
             let result = self.ptr.cast::<T>().read_unaligned();
-            self.ptr = self.ptr.byte_add(mem::size_of::<T>());
+            self.ptr = self.ptr.byte_add(size_of::<T>());
             result
         }
     }
diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs
new file mode 100644
index 00000000000..2a9167bfe96
--- /dev/null
+++ b/library/std/src/sys/stdio/mod.rs
@@ -0,0 +1,38 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_family = "unix",
+        target_os = "hermit"
+    ))] {
+        mod unix;
+        pub use unix::*;
+    } else if #[cfg(target_os = "windows")] {
+        mod windows;
+        pub use windows::*;
+    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+        mod sgx;
+        pub use sgx::*;
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod solid;
+        pub use solid::*;
+    } else if #[cfg(target_os = "teeos")] {
+        mod teeos;
+        pub use teeos::*;
+    } else if #[cfg(target_os = "uefi")] {
+        mod uefi;
+        pub use uefi::*;
+    } else if #[cfg(target_os = "wasi")] {
+        mod wasi;
+        pub use wasi::*;
+    } else if #[cfg(target_os = "xous")] {
+        mod xous;
+        pub use xous::*;
+    } else if #[cfg(target_os = "zkvm")] {
+        mod zkvm;
+        pub use zkvm::*;
+    } else {
+        mod unsupported;
+        pub use unsupported::*;
+    }
+}
diff --git a/library/std/src/sys/pal/sgx/stdio.rs b/library/std/src/sys/stdio/sgx.rs
index 726a93acae4..03d754cb217 100644
--- a/library/std/src/sys/pal/sgx/stdio.rs
+++ b/library/std/src/sys/stdio/sgx.rs
@@ -1,10 +1,6 @@
 use fortanix_sgx_abi as abi;
 
 use crate::io;
-#[cfg(not(test))]
-use crate::slice;
-#[cfg(not(test))]
-use crate::str;
 use crate::sys::fd::FileDesc;
 
 pub struct Stdin(());
@@ -70,19 +66,5 @@ pub fn is_ebadf(err: &io::Error) -> bool {
 }
 
 pub fn panic_output() -> Option<impl io::Write> {
-    super::abi::panic::SgxPanicOutput::new()
-}
-
-// This function is needed by libunwind. The symbol is named in pre-link args
-// for the target specification, so keep that in sync.
-#[cfg(not(test))]
-#[unsafe(no_mangle)]
-pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
-    if s < 0 {
-        return;
-    }
-    let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
-    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
-        eprint!("{s}");
-    }
+    crate::sys::pal::abi::panic::SgxPanicOutput::new()
 }
diff --git a/library/std/src/sys/pal/solid/stdio.rs b/library/std/src/sys/stdio/solid.rs
index 50f0176967b..a2ff4bb212f 100644
--- a/library/std/src/sys/pal/solid/stdio.rs
+++ b/library/std/src/sys/stdio/solid.rs
@@ -1,5 +1,5 @@
-use super::abi;
 use crate::io;
+use crate::sys::pal::abi;
 
 pub struct Stdin;
 pub struct Stdout;
diff --git a/library/std/src/sys/pal/teeos/stdio.rs b/library/std/src/sys/stdio/teeos.rs
index 67e251812da..67e251812da 100644
--- a/library/std/src/sys/pal/teeos/stdio.rs
+++ b/library/std/src/sys/stdio/teeos.rs
diff --git a/library/std/src/sys/pal/uefi/stdio.rs b/library/std/src/sys/stdio/uefi.rs
index 257e321dd03..257e321dd03 100644
--- a/library/std/src/sys/pal/uefi/stdio.rs
+++ b/library/std/src/sys/stdio/uefi.rs
diff --git a/library/std/src/sys/pal/unix/stdio.rs b/library/std/src/sys/stdio/unix.rs
index 8c2f61a40de..08a06e0da9f 100644
--- a/library/std/src/sys/pal/unix/stdio.rs
+++ b/library/std/src/sys/stdio/unix.rs
@@ -1,5 +1,13 @@
+#[cfg(target_os = "hermit")]
+use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
+#[cfg(target_family = "unix")]
+use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
+
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
+#[cfg(target_os = "hermit")]
+use crate::os::hermit::io::FromRawFd;
+#[cfg(target_family = "unix")]
 use crate::os::unix::io::FromRawFd;
 use crate::sys::fd::FileDesc;
 
@@ -15,15 +23,15 @@ impl Stdin {
 
 impl io::Read for Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read(buf) }
     }
 
     fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_buf(buf) }
     }
 
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_vectored(bufs) }
     }
 
     #[inline]
@@ -40,13 +48,11 @@ impl Stdout {
 
 impl io::Write for Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write(buf) }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDOUT_FILENO)).write(buf) }
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsafe {
-            ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write_vectored(bufs)
-        }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDOUT_FILENO)).write_vectored(bufs) }
     }
 
     #[inline]
@@ -68,13 +74,11 @@ impl Stderr {
 
 impl io::Write for Stderr {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write(buf) }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDERR_FILENO)).write(buf) }
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsafe {
-            ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write_vectored(bufs)
-        }
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDERR_FILENO)).write_vectored(bufs) }
     }
 
     #[inline]
@@ -89,7 +93,7 @@ impl io::Write for Stderr {
 }
 
 pub fn is_ebadf(err: &io::Error) -> bool {
-    err.raw_os_error() == Some(libc::EBADF as i32)
+    err.raw_os_error() == Some(EBADF as i32)
 }
 
 pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
diff --git a/library/std/src/sys/pal/unsupported/stdio.rs b/library/std/src/sys/stdio/unsupported.rs
index b5e3f5be988..b5e3f5be988 100644
--- a/library/std/src/sys/pal/unsupported/stdio.rs
+++ b/library/std/src/sys/stdio/unsupported.rs
diff --git a/library/std/src/sys/pal/wasi/stdio.rs b/library/std/src/sys/stdio/wasi.rs
index fb21cb4d393..8105b0cfa2f 100644
--- a/library/std/src/sys/pal/wasi/stdio.rs
+++ b/library/std/src/sys/stdio/wasi.rs
@@ -1,10 +1,10 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-use super::fd::WasiFd;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
 use crate::os::raw;
 use crate::os::wasi::io::{AsRawFd, FromRawFd};
+use crate::sys::pal::fd::WasiFd;
 
 pub struct Stdin;
 pub struct Stdout;
diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/stdio/windows.rs
index 1b245991aa7..9b27f76b9dd 100644
--- a/library/std/src/sys/pal/windows/stdio.rs
+++ b/library/std/src/sys/stdio/windows.rs
@@ -3,10 +3,10 @@
 use core::char::MAX_LEN_UTF8;
 use core::str::utf8_char_width;
 
-use super::api::{self, WinError};
 use crate::mem::MaybeUninit;
 use crate::os::windows::io::{FromRawHandle, IntoRawHandle};
 use crate::sys::handle::Handle;
+use crate::sys::pal::api::{self, WinError};
 use crate::sys::{c, cvt};
 use crate::{cmp, io, ptr, str};
 
@@ -359,7 +359,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
     const CTRL_Z: u16 = 0x1A;
     const CTRL_Z_MASK: u32 = 1 << CTRL_Z;
     let input_control = c::CONSOLE_READCONSOLE_CONTROL {
-        nLength: crate::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as u32,
+        nLength: size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as u32,
         nInitialChars: 0,
         dwCtrlWakeupMask: CTRL_Z_MASK,
         dwControlKeyState: 0,
diff --git a/library/std/src/sys/pal/windows/stdio/tests.rs b/library/std/src/sys/stdio/windows/tests.rs
index 1e53e0bee63..1e53e0bee63 100644
--- a/library/std/src/sys/pal/windows/stdio/tests.rs
+++ b/library/std/src/sys/stdio/windows/tests.rs
diff --git a/library/std/src/sys/pal/xous/stdio.rs b/library/std/src/sys/stdio/xous.rs
index dfd47a1775a..71736145221 100644
--- a/library/std/src/sys/pal/xous/stdio.rs
+++ b/library/std/src/sys/stdio/xous.rs
@@ -87,7 +87,7 @@ pub struct PanicWriter {
 
 impl io::Write for PanicWriter {
     fn write(&mut self, s: &[u8]) -> core::result::Result<usize, io::Error> {
-        for c in s.chunks(core::mem::size_of::<usize>() * 4) {
+        for c in s.chunks(size_of::<usize>() * 4) {
             // Text is grouped into 4x `usize` words. The id is 1100 plus
             // the number of characters in this message.
             // Ignore errors since we're already panicking.
diff --git a/library/std/src/sys/pal/zkvm/stdio.rs b/library/std/src/sys/stdio/zkvm.rs
index 0bcb54744b0..f31c6c26e87 100644
--- a/library/std/src/sys/pal/zkvm/stdio.rs
+++ b/library/std/src/sys/stdio/zkvm.rs
@@ -1,6 +1,5 @@
-use super::abi;
-use super::abi::fileno;
 use crate::io::{self, BorrowedCursor};
+use crate::sys::pal::abi::{self, fileno};
 
 pub struct Stdin;
 pub struct Stdout;
diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs
index 55ac5b20e1a..48dfe17ab32 100644
--- a/library/std/src/sys/thread_local/key/xous.rs
+++ b/library/std/src/sys/thread_local/key/xous.rs
@@ -85,7 +85,7 @@ fn tls_table() -> &'static mut [*mut u8] {
 
     if !tp.is_null() {
         return unsafe {
-            core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / core::mem::size_of::<*mut u8>())
+            core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / size_of::<*mut u8>())
         };
     }
     // If the TP register is `0`, then this thread hasn't initialized
@@ -94,7 +94,7 @@ fn tls_table() -> &'static mut [*mut u8] {
         map_memory(
             None,
             None,
-            TLS_MEMORY_SIZE / core::mem::size_of::<*mut u8>(),
+            TLS_MEMORY_SIZE / size_of::<*mut u8>(),
             MemoryFlags::R | MemoryFlags::W,
         )
         .expect("Unable to allocate memory for thread local storage")
@@ -177,11 +177,8 @@ pub unsafe fn destroy_tls() {
 
     // Finally, free the TLS array
     unsafe {
-        unmap_memory(core::slice::from_raw_parts_mut(
-            tp,
-            TLS_MEMORY_SIZE / core::mem::size_of::<usize>(),
-        ))
-        .unwrap()
+        unmap_memory(core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / size_of::<usize>()))
+            .unwrap()
     };
 }
 
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 4dc67d26bd8..2a5de7f6666 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -20,7 +20,6 @@
 #[cfg(test)]
 mod tests;
 
-pub mod fs;
 pub mod process;
 pub mod wstr;
 pub mod wtf8;
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index ff45e82bd9c..06c347af181 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -1,12 +1,12 @@
 use super::Builder;
 use crate::any::Any;
 use crate::panic::panic_any;
+use crate::result;
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::mpsc::{Sender, channel};
 use crate::sync::{Arc, Barrier};
 use crate::thread::{self, Scope, ThreadId};
 use crate::time::{Duration, Instant};
-use crate::{mem, result};
 
 // !!! These tests are dangerous. If something is buggy, they will hang, !!!
 // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
@@ -327,7 +327,7 @@ fn sleep_ms_smoke() {
 
 #[test]
 fn test_size_of_option_thread_id() {
-    assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
+    assert_eq!(size_of::<Option<ThreadId>>(), size_of::<ThreadId>());
 }
 
 #[test]
diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs
index 1b94005ab6c..fa8a8c38583 100644
--- a/library/unwind/src/unwinding.rs
+++ b/library/unwind/src/unwinding.rs
@@ -39,9 +39,9 @@ pub type _Unwind_Exception_Class = u64;
 pub type _Unwind_Word = *const u8;
 pub type _Unwind_Ptr = *const u8;
 
-pub const unwinder_private_data_size: usize = core::mem::size_of::<UnwindException>()
-    - core::mem::size_of::<_Unwind_Exception_Class>()
-    - core::mem::size_of::<_Unwind_Exception_Cleanup_Fn>();
+pub const unwinder_private_data_size: usize = size_of::<UnwindException>()
+    - size_of::<_Unwind_Exception_Class>()
+    - size_of::<_Unwind_Exception_Cleanup_Fn>();
 
 pub type _Unwind_Exception_Cleanup_Fn =
     Option<extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception)>;
diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs
index e89bde8b1ab..939fab7d5fe 100644
--- a/library/windows_targets/src/lib.rs
+++ b/library/windows_targets/src/lib.rs
@@ -34,7 +34,7 @@ pub macro link {
 }
 
 #[cfg(not(feature = "windows_raw_dylib"))]
-#[link(name = "advapi32")]
+#[cfg_attr(target_vendor = "win7", link(name = "advapi32"))]
 #[link(name = "ntdll")]
 #[link(name = "userenv")]
 #[link(name = "ws2_32")]
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 88aa70d4f2f..6cb0b19d763 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -56,6 +56,7 @@ check-aux:
 	# Run standard library tests in Miri.
 	$(Q)$(BOOTSTRAP) miri --stage 2 \
 		library/coretests \
+		library/alloctests \
 		library/alloc \
 		$(BOOTSTRAP_ARGS) \
 		--no-doc
@@ -63,6 +64,7 @@ check-aux:
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 \
 		library/coretests \
+		library/alloctests \
 		library/alloc \
 		$(BOOTSTRAP_ARGS) \
 		--doc
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index 38b380e3db8..6f6aaa878ef 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -70,11 +70,12 @@ fn main() {
     }
 
     // check_version warnings are not printed during setup, or during CI
-    let changelog_suggestion = if matches!(config.cmd, Subcommand::Setup { .. }) || CiEnv::is_ci() {
-        None
-    } else {
-        check_version(&config)
-    };
+    let changelog_suggestion =
+        if matches!(config.cmd, Subcommand::Setup { .. }) || CiEnv::is_ci() || config.dry_run() {
+            None
+        } else {
+            check_version(&config)
+        };
 
     // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
     // changelog warning, not the `x.py setup` message.
@@ -187,7 +188,7 @@ fn check_version(config: &Config) -> Option<String> {
             "update `config.toml` to use `change-id = {latest_change_id}` instead"
         ));
 
-        if io::stdout().is_terminal() && !config.dry_run() {
+        if io::stdout().is_terminal() {
             t!(fs::write(warned_id_path, latest_change_id.to_string()));
         }
     } else {
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 61045067592..d8cae02456c 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -349,7 +349,7 @@ fn format_rusage_data(child: Child) -> Option<String> {
     let mut kernel_filetime = Default::default();
     let mut kernel_time = Default::default();
     let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
-    let memory_counters_size = std::mem::size_of_val(&memory_counters);
+    let memory_counters_size = size_of_val(&memory_counters);
 
     unsafe {
         GetProcessTimes(
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index b8bbe1eb5f8..18aa3119842 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -45,7 +45,10 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library")
+        run.crate_or_deps("sysroot")
+            .crate_or_deps("coretests")
+            .crate_or_deps("alloctests")
+            .path("library")
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 78219500737..319a2233b1c 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -2020,7 +2020,9 @@ impl Step for Assemble {
                 builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage=target_compiler.stage));
             }
 
-            maybe_install_llvm_bitcode_linker(target_compiler);
+            let mut precompiled_compiler = target_compiler;
+            precompiled_compiler.forced_compiler(true);
+            maybe_install_llvm_bitcode_linker(precompiled_compiler);
 
             return target_compiler;
         }
@@ -2203,7 +2205,7 @@ impl Step for Assemble {
             );
         }
 
-        maybe_install_llvm_bitcode_linker(build_compiler);
+        maybe_install_llvm_bitcode_linker(target_compiler);
 
         // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
         // so that it can be found when the newly built `rustc` is run.
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 0296346009f..ec0edeab996 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -230,8 +230,10 @@ fn make_win_dist(
         "libiconv.a",
         "libmoldname.a",
         "libpthread.a",
-        //Windows import libs
-        //This should contain only the set of libraries necessary to link the standard library.
+        // Windows import libs
+        // This *should* contain only the set of libraries necessary to link the standard library,
+        // however we've had problems with people accidentally depending on extra libs being here,
+        // so we can't easily remove entries.
         "libadvapi32.a",
         "libbcrypt.a",
         "libcomctl32.a",
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index e8b6a577cea..70789fbbeeb 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -125,6 +125,7 @@ impl Step for Gcc {
         t!(stamp.remove());
         let _time = helpers::timeit(builder);
         t!(fs::create_dir_all(&out_dir));
+        t!(fs::create_dir_all(&install_dir));
 
         let libgccjit_path = libgccjit_built_path(&install_dir);
         if builder.config.dry_run() {
@@ -185,8 +186,16 @@ impl Step for Gcc {
         }
         configure_cmd.run(builder);
 
-        command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder);
-        command("make").current_dir(&out_dir).arg("install").run(builder);
+        command("make")
+            .current_dir(&out_dir)
+            .arg("--silent")
+            .arg(format!("-j{}", builder.jobs()))
+            .run_capture_stdout(builder);
+        command("make")
+            .current_dir(&out_dir)
+            .arg("--silent")
+            .arg("install")
+            .run_capture_stdout(builder);
 
         let lib_alias = install_dir.join("lib/libgccjit.so.0");
         if !lib_alias.exists() {
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index fea8232296e..1ef86e674f0 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -367,3 +367,28 @@ impl Step for FeaturesStatusDump {
         cmd.run(builder);
     }
 }
+
+/// Dummy step that can be used to deliberately trigger bootstrap's step cycle
+/// detector, for automated and manual testing.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct CyclicStep {
+    n: u32,
+}
+
+impl Step for CyclicStep {
+    type Output = ();
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("cyclic-step")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        // Start with n=2, so that we build up a few stack entries before panicking.
+        run.builder.ensure(CyclicStep { n: 2 })
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        // When n=0, the step will try to ensure itself, causing a step cycle.
+        builder.ensure(CyclicStep { n: self.n.saturating_sub(1) })
+    }
+}
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 4b7c8d5770e..e80f8f9a4b7 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2609,7 +2609,7 @@ impl Step for Crate {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.crate_or_deps("sysroot").crate_or_deps("coretests")
+        run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2724,12 +2724,16 @@ impl Step for Crate {
         };
 
         let mut crates = self.crates.clone();
-        // The core crate can't directly be tested. We could silently
-        // ignore it, but adding it's own test crate is less confusing
-        // for users. We still keep core itself for doctests.
+        // The core and alloc crates can't directly be tested. We
+        // could silently ignore them, but adding their own test
+        // crates is less confusing for users. We still keep core and
+        // alloc themself for doctests
         if crates.iter().any(|crate_| crate_ == "core") {
             crates.push("coretests".to_owned());
         }
+        if crates.iter().any(|crate_| crate_ == "alloc") {
+            crates.push("alloctests".to_owned());
+        }
 
         run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder);
     }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 65633c9ea7c..e0cf2c12139 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -121,10 +121,18 @@ impl Step for ToolBuild {
 
         match self.mode {
             Mode::ToolRustc => {
-                builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
-                builder.ensure(compile::Rustc::new(self.compiler, target));
+                // If compiler was forced, its artifacts should be prepared earlier.
+                if !self.compiler.is_forced_compiler() {
+                    builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
+                    builder.ensure(compile::Rustc::new(self.compiler, target));
+                }
+            }
+            Mode::ToolStd => {
+                // If compiler was forced, its artifacts should be prepared earlier.
+                if !self.compiler.is_forced_compiler() {
+                    builder.ensure(compile::Std::new(self.compiler, target))
+                }
             }
-            Mode::ToolStd => builder.ensure(compile::Std::new(self.compiler, target)),
             Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
             _ => panic!("unexpected Mode for tool build"),
         }
@@ -319,18 +327,20 @@ pub(crate) fn get_tool_rustc_compiler(
     builder: &Builder<'_>,
     target_compiler: Compiler,
 ) -> Compiler {
-    if builder.download_rustc() && target_compiler.stage == 1 {
-        // We already have the stage 1 compiler, we don't need to cut the stage.
-        builder.compiler(target_compiler.stage, builder.config.build)
-    } else if target_compiler.is_forced_compiler() {
-        target_compiler
-    } else {
-        // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
-        // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage
-        // compilers, which isn't what we want. Rustc tools should be linked in the same way as the
-        // compiler it's paired with, so it must be built with the previous stage compiler.
-        builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build)
+    if target_compiler.is_forced_compiler() {
+        return target_compiler;
     }
+
+    if builder.download_rustc() && target_compiler.stage > 0 {
+        // We already have the stage N compiler, we don't need to cut the stage.
+        return builder.compiler(target_compiler.stage, builder.config.build);
+    }
+
+    // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
+    // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage
+    // compilers, which isn't what we want. Rustc tools should be linked in the same way as the
+    // compiler it's paired with, so it must be built with the previous stage compiler.
+    builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build)
 }
 
 /// Links a built tool binary with the given `name` from the build directory to the
@@ -1191,13 +1201,23 @@ fn run_tool_build_step(
     }
 }
 
-tool_extended!(Cargofmt { path: "src/tools/rustfmt", tool_name: "cargo-fmt", stable: true });
-tool_extended!(CargoClippy { path: "src/tools/clippy", tool_name: "cargo-clippy", stable: true });
+tool_extended!(Cargofmt {
+    path: "src/tools/rustfmt",
+    tool_name: "cargo-fmt",
+    stable: true,
+    add_bins_to_sysroot: ["cargo-fmt"]
+});
+tool_extended!(CargoClippy {
+    path: "src/tools/clippy",
+    tool_name: "cargo-clippy",
+    stable: true,
+    add_bins_to_sysroot: ["cargo-clippy"]
+});
 tool_extended!(Clippy {
     path: "src/tools/clippy",
     tool_name: "clippy-driver",
     stable: true,
-    add_bins_to_sysroot: ["clippy-driver", "cargo-clippy"]
+    add_bins_to_sysroot: ["clippy-driver"]
 });
 tool_extended!(Miri {
     path: "src/tools/miri",
@@ -1216,7 +1236,7 @@ tool_extended!(Rustfmt {
     path: "src/tools/rustfmt",
     tool_name: "rustfmt",
     stable: true,
-    add_bins_to_sysroot: ["rustfmt", "cargo-fmt"]
+    add_bins_to_sysroot: ["rustfmt"]
 });
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index d1d52d82eaa..12dd40d14e9 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -597,7 +597,7 @@ impl Builder<'_> {
         // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
         // library unnecessary. This can be removed when windows-rs enables raw-dylib
         // unconditionally.
-        if let Mode::Rustc | Mode::ToolRustc = mode {
+        if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode {
             rustflags.arg("--cfg=windows_raw_dylib");
         }
 
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 801894e9ff1..8e1cecfcd18 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -50,7 +50,7 @@ pub struct Builder<'a> {
 
     /// A stack of [`Step`]s to run before we can run this builder. The output
     /// of steps is cached in [`Self::cache`].
-    stack: RefCell<Vec<Box<dyn Any>>>,
+    stack: RefCell<Vec<Box<dyn AnyDebug>>>,
 
     /// The total amount of time we spent running [`Step`]s in [`Self::stack`].
     time_spent_on_dependencies: Cell<Duration>,
@@ -69,6 +69,21 @@ impl Deref for Builder<'_> {
     }
 }
 
+/// This trait is similar to `Any`, except that it also exposes the underlying
+/// type's [`Debug`] implementation.
+///
+/// (Trying to debug-print `dyn Any` results in the unhelpful `"Any { .. }"`.)
+trait AnyDebug: Any + Debug {}
+impl<T: Any + Debug> AnyDebug for T {}
+impl dyn AnyDebug {
+    /// Equivalent to `<dyn Any>::downcast_ref`.
+    fn downcast_ref<T: Any>(&self) -> Option<&T> {
+        (self as &dyn Any).downcast_ref()
+    }
+
+    // Feel free to add other `dyn Any` methods as necessary.
+}
+
 pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
     /// Result type of `Step::run`.
     type Output: Clone;
@@ -890,6 +905,7 @@ impl<'a> Builder<'a> {
                 gcc::Gcc,
                 llvm::Sanitizers,
                 tool::Rustfmt,
+                tool::Cargofmt,
                 tool::Miri,
                 tool::CargoMiri,
                 llvm::Lld,
@@ -1101,6 +1117,7 @@ impl<'a> Builder<'a> {
                 run::GenerateCompletions,
                 run::UnicodeTableGenerator,
                 run::FeaturesStatusDump,
+                run::CyclicStep,
             ),
             Kind::Setup => {
                 describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor)
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 63a1bbc24f1..e8820e3a828 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -1,4 +1,4 @@
-use std::thread;
+use std::{panic, thread};
 
 use llvm::prebuilt_llvm_config;
 
@@ -1135,3 +1135,35 @@ fn test_get_tool_rustc_compiler() {
     let actual = tool::get_tool_rustc_compiler(&builder, compiler);
     assert_eq!(expected, actual);
 }
+
+/// When bootstrap detects a step dependency cycle (which is a bug), its panic
+/// message should show the actual steps on the stack, not just several copies
+/// of `Any { .. }`.
+#[test]
+fn step_cycle_debug() {
+    let cmd = ["run", "cyclic-step"].map(str::to_owned);
+    let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+
+    let err = panic::catch_unwind(|| run_build(&config.paths.clone(), config)).unwrap_err();
+    let err = err.downcast_ref::<String>().unwrap().as_str();
+
+    assert!(!err.contains("Any"));
+    assert!(err.contains("CyclicStep { n: 1 }"));
+}
+
+/// The `AnyDebug` trait should delegate to the underlying type's `Debug`, and
+/// should also allow downcasting as expected.
+#[test]
+fn any_debug() {
+    #[derive(Debug, PartialEq, Eq)]
+    struct MyStruct {
+        x: u32,
+    }
+
+    let x: &dyn AnyDebug = &MyStruct { x: 7 };
+
+    // Debug-formatting should delegate to the underlying type.
+    assert_eq!(format!("{x:?}"), format!("{:?}", MyStruct { x: 7 }));
+    // Downcasting to the underlying type should succeed.
+    assert_eq!(x.downcast_ref::<MyStruct>(), Some(&MyStruct { x: 7 }));
+}
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 788c8bbdc84..994ccabf0eb 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -96,7 +96,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
 pub struct Compiler {
     stage: u32,
     host: TargetSelection,
-    /// Indicates whether `compiler_for` was used to force a specific compiler stage.
+    /// Indicates whether the compiler was forced to use a specific stage.
     /// This field is ignored in `Hash` and `PartialEq` implementations as only the `stage`
     /// and `host` fields are relevant for those.
     forced_compiler: bool,
@@ -1998,7 +1998,7 @@ impl Compiler {
         self.stage == 0 && self.host == build.build
     }
 
-    /// Indicates whether `compiler_for` was used to force a specific compiler stage.
+    /// Indicates whether the compiler was forced to use a specific stage.
     pub fn is_forced_compiler(&self) -> bool {
         self.forced_compiler
     }
diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs
index 10efed130d6..a60e889fd57 100644
--- a/src/bootstrap/src/utils/job.rs
+++ b/src/bootstrap/src/utils/job.rs
@@ -42,7 +42,7 @@ pub unsafe fn setup(build: &mut crate::Build) {
 #[cfg(windows)]
 mod for_windows {
     use std::ffi::c_void;
-    use std::{io, mem};
+    use std::io;
 
     use windows::Win32::Foundation::CloseHandle;
     use windows::Win32::System::Diagnostics::Debug::{
@@ -82,7 +82,7 @@ mod for_windows {
             job,
             JobObjectExtendedLimitInformation,
             &info as *const _ as *const c_void,
-            mem::size_of_val(&info) as u32,
+            size_of_val(&info) as u32,
         );
         assert!(r.is_ok(), "{}", io::Error::last_os_error());
 
diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 3ef9c7ac35e..9f778a2fd77 100644
--- a/src/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
@@ -129,7 +129,7 @@ pub fn get_closest_merge_commit(
         git.current_dir(git_dir);
     }
 
-    let channel = include_str!("../../ci/channel");
+    let channel = include_str!("../../ci/channel").trim();
 
     let merge_base = {
         if CiEnv::is_ci() &&
diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs
index eb306550fc4..b6daac32a44 100644
--- a/src/build_helper/src/metrics.rs
+++ b/src/build_helper/src/metrics.rs
@@ -74,7 +74,7 @@ pub struct Test {
     pub outcome: TestOutcome,
 }
 
-#[derive(Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
 #[serde(tag = "outcome", rename_all = "snake_case")]
 pub enum TestOutcome {
     Passed,
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index a1e5658be36..52e7638d98b 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -1,5 +1,6 @@
 mod cpu_usage;
 mod datadog;
+mod merge_report;
 mod metrics;
 mod utils;
 
@@ -13,6 +14,7 @@ use serde_yaml::Value;
 
 use crate::cpu_usage::load_cpu_usage;
 use crate::datadog::upload_datadog_metric;
+use crate::merge_report::post_merge_report;
 use crate::metrics::postprocess_metrics;
 use crate::utils::load_env_var;
 
@@ -182,6 +184,10 @@ fn yaml_map_to_json(map: &BTreeMap<String, Value>) -> BTreeMap<String, serde_jso
         .collect()
 }
 
+/// Maximum number of custom try jobs that can be requested in a single
+/// `@bors try` request.
+const MAX_TRY_JOBS_COUNT: usize = 20;
+
 fn calculate_jobs(
     run_type: &RunType,
     db: &JobDatabase,
@@ -191,9 +197,9 @@ fn calculate_jobs(
         RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env),
         RunType::TryJob { custom_jobs } => {
             let jobs = if let Some(custom_jobs) = custom_jobs {
-                if custom_jobs.len() > 10 {
+                if custom_jobs.len() > MAX_TRY_JOBS_COUNT {
                     return Err(anyhow::anyhow!(
-                        "It is only possible to schedule up to 10 custom jobs, received {} custom jobs",
+                        "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs",
                         custom_jobs.len()
                     ));
                 }
@@ -369,6 +375,13 @@ enum Args {
         /// Path to a CSV containing the CI job CPU usage.
         cpu_usage_csv: PathBuf,
     },
+    /// Generate a report of test execution changes between two rustc commits.
+    PostMergeReport {
+        /// Parent commit to use as a base of the comparison.
+        parent: String,
+        /// Current commit that will be compared to `parent`.
+        current: String,
+    },
 }
 
 #[derive(clap::ValueEnum, Clone)]
@@ -406,6 +419,9 @@ fn main() -> anyhow::Result<()> {
         Args::PostprocessMetrics { metrics_path, summary_path } => {
             postprocess_metrics(&metrics_path, &summary_path)?;
         }
+        Args::PostMergeReport { current: commit, parent } => {
+            post_merge_report(load_db(default_jobs_file)?, parent, commit)?;
+        }
     }
 
     Ok(())
diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/merge_report.rs
new file mode 100644
index 00000000000..5dd662280f0
--- /dev/null
+++ b/src/ci/citool/src/merge_report.rs
@@ -0,0 +1,257 @@
+use std::cmp::Reverse;
+use std::collections::HashMap;
+
+use anyhow::Context;
+use build_helper::metrics::{JsonRoot, TestOutcome};
+
+use crate::JobDatabase;
+use crate::metrics::get_test_suites;
+
+type Sha = String;
+type JobName = String;
+
+/// Computes a post merge CI analysis report between the `parent` and `current` commits.
+pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> {
+    let jobs = download_all_metrics(&job_db, &parent, &current)?;
+    let diffs = aggregate_test_diffs(&jobs)?;
+    report_test_changes(diffs);
+
+    Ok(())
+}
+
+struct JobMetrics {
+    parent: Option<JsonRoot>,
+    current: JsonRoot,
+}
+
+/// Download before/after metrics for all auto jobs in the job database.
+fn download_all_metrics(
+    job_db: &JobDatabase,
+    parent: &str,
+    current: &str,
+) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
+    let mut jobs = HashMap::default();
+
+    for job in &job_db.auto_jobs {
+        eprintln!("Downloading metrics of job {}", job.name);
+        let metrics_parent = match download_job_metrics(&job.name, parent) {
+            Ok(metrics) => Some(metrics),
+            Err(error) => {
+                eprintln!(
+                    r#"Did not find metrics for job `{}` at `{}`: {error:?}.
+Maybe it was newly added?"#,
+                    job.name, parent
+                );
+                None
+            }
+        };
+        let metrics_current = download_job_metrics(&job.name, current)?;
+        jobs.insert(
+            job.name.clone(),
+            JobMetrics { parent: metrics_parent, current: metrics_current },
+        );
+    }
+    Ok(jobs)
+}
+
+fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
+    let url = get_metrics_url(job_name, sha);
+    let mut response = ureq::get(&url).call()?;
+    if !response.status().is_success() {
+        return Err(anyhow::anyhow!(
+            "Cannot fetch metrics from {url}: {}\n{}",
+            response.status(),
+            response.body_mut().read_to_string()?
+        ));
+    }
+    let data: JsonRoot = response
+        .body_mut()
+        .read_json()
+        .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;
+    Ok(data)
+}
+
+fn get_metrics_url(job_name: &str, sha: &str) -> String {
+    let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" };
+    format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json")
+}
+
+fn aggregate_test_diffs(
+    jobs: &HashMap<JobName, JobMetrics>,
+) -> anyhow::Result<Vec<AggregatedTestDiffs>> {
+    let mut job_diffs = vec![];
+
+    // Aggregate test suites
+    for (name, metrics) in jobs {
+        if let Some(parent) = &metrics.parent {
+            let tests_parent = aggregate_tests(parent);
+            let tests_current = aggregate_tests(&metrics.current);
+            let test_diffs = calculate_test_diffs(tests_parent, tests_current);
+            if !test_diffs.is_empty() {
+                job_diffs.push((name.clone(), test_diffs));
+            }
+        }
+    }
+
+    // Aggregate jobs with the same diff, as often the same diff will appear in many jobs
+    let job_diffs: HashMap<Vec<(Test, TestOutcomeDiff)>, Vec<String>> =
+        job_diffs.into_iter().fold(HashMap::new(), |mut acc, (job, diffs)| {
+            acc.entry(diffs).or_default().push(job);
+            acc
+        });
+
+    Ok(job_diffs
+        .into_iter()
+        .map(|(test_diffs, jobs)| AggregatedTestDiffs { jobs, test_diffs })
+        .collect())
+}
+
+fn calculate_test_diffs(
+    reference: TestSuiteData,
+    current: TestSuiteData,
+) -> Vec<(Test, TestOutcomeDiff)> {
+    let mut diffs = vec![];
+    for (test, outcome) in &current.tests {
+        match reference.tests.get(test) {
+            Some(before) => {
+                if before != outcome {
+                    diffs.push((
+                        test.clone(),
+                        TestOutcomeDiff::ChangeOutcome {
+                            before: before.clone(),
+                            after: outcome.clone(),
+                        },
+                    ));
+                }
+            }
+            None => diffs.push((test.clone(), TestOutcomeDiff::Added(outcome.clone()))),
+        }
+    }
+    for (test, outcome) in &reference.tests {
+        if !current.tests.contains_key(test) {
+            diffs.push((test.clone(), TestOutcomeDiff::Missing { before: outcome.clone() }));
+        }
+    }
+
+    diffs
+}
+
+/// Represents a difference in the outcome of tests between a base and a current commit.
+#[derive(Debug)]
+struct AggregatedTestDiffs {
+    /// All jobs that had the exact same test diffs.
+    jobs: Vec<String>,
+    test_diffs: Vec<(Test, TestOutcomeDiff)>,
+}
+
+#[derive(Eq, PartialEq, Hash, Debug)]
+enum TestOutcomeDiff {
+    ChangeOutcome { before: TestOutcome, after: TestOutcome },
+    Missing { before: TestOutcome },
+    Added(TestOutcome),
+}
+
+/// Aggregates test suite executions from all bootstrap invocations in a given CI job.
+#[derive(Default)]
+struct TestSuiteData {
+    tests: HashMap<Test, TestOutcome>,
+}
+
+#[derive(Hash, PartialEq, Eq, Debug, Clone)]
+struct Test {
+    name: String,
+}
+
+/// Extracts all tests from the passed metrics and map them to their outcomes.
+fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
+    let mut tests = HashMap::new();
+    let test_suites = get_test_suites(&metrics);
+    for suite in test_suites {
+        for test in &suite.tests {
+            let test_entry = Test { name: normalize_test_name(&test.name) };
+            tests.insert(test_entry, test.outcome.clone());
+        }
+    }
+    TestSuiteData { tests }
+}
+
+/// Normalizes Windows-style path delimiters to Unix-style paths.
+fn normalize_test_name(name: &str) -> String {
+    name.replace('\\', "/")
+}
+
+/// Prints test changes in Markdown format to stdout.
+fn report_test_changes(mut diffs: Vec<AggregatedTestDiffs>) {
+    println!("## Test differences");
+    if diffs.is_empty() {
+        println!("No test diffs found");
+        return;
+    }
+
+    // Sort diffs in decreasing order by diff count
+    diffs.sort_by_key(|entry| Reverse(entry.test_diffs.len()));
+
+    fn format_outcome(outcome: &TestOutcome) -> String {
+        match outcome {
+            TestOutcome::Passed => "pass".to_string(),
+            TestOutcome::Failed => "fail".to_string(),
+            TestOutcome::Ignored { ignore_reason } => {
+                let reason = match ignore_reason {
+                    Some(reason) => format!(" ({reason})"),
+                    None => String::new(),
+                };
+                format!("ignore{reason}")
+            }
+        }
+    }
+
+    fn format_diff(diff: &TestOutcomeDiff) -> String {
+        match diff {
+            TestOutcomeDiff::ChangeOutcome { before, after } => {
+                format!("{} -> {}", format_outcome(before), format_outcome(after))
+            }
+            TestOutcomeDiff::Missing { before } => {
+                format!("{} -> [missing]", format_outcome(before))
+            }
+            TestOutcomeDiff::Added(outcome) => {
+                format!("[missing] -> {}", format_outcome(outcome))
+            }
+        }
+    }
+
+    let max_diff_count = 10;
+    let max_job_count = 5;
+    let max_test_count = 10;
+
+    for diff in diffs.iter().take(max_diff_count) {
+        let mut jobs = diff.jobs.clone();
+        jobs.sort();
+
+        let jobs = jobs.iter().take(max_job_count).map(|j| format!("`{j}`")).collect::<Vec<_>>();
+
+        let extra_jobs = diff.jobs.len().saturating_sub(max_job_count);
+        let suffix = if extra_jobs > 0 {
+            format!(" (and {extra_jobs} {})", pluralize("other", extra_jobs))
+        } else {
+            String::new()
+        };
+        println!("- {}{suffix}", jobs.join(","));
+
+        let extra_tests = diff.test_diffs.len().saturating_sub(max_test_count);
+        for (test, outcome_diff) in diff.test_diffs.iter().take(max_test_count) {
+            println!("  - {}: {}", test.name, format_diff(&outcome_diff));
+        }
+        if extra_tests > 0 {
+            println!("  - (and {extra_tests} additional {})", pluralize("tests", extra_tests));
+        }
+    }
+
+    let extra_diffs = diffs.len().saturating_sub(max_diff_count);
+    if extra_diffs > 0 {
+        println!("\n(and {extra_diffs} additional {})", pluralize("diff", extra_diffs));
+    }
+}
+
+fn pluralize(text: &str, count: usize) -> String {
+    if count == 1 { text.to_string() } else { format!("{text}s") }
+}
diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs
index 2386413ed6b..83b3d5ceed0 100644
--- a/src/ci/citool/src/metrics.rs
+++ b/src/ci/citool/src/metrics.rs
@@ -67,6 +67,10 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
     let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed  ❌ |\n".to_string();
     writeln!(table, "|:------|------:|------:|------:|").unwrap();
 
+    fn compute_pct(value: f64, total: f64) -> f64 {
+        if total == 0.0 { 0.0 } else { value / total }
+    }
+
     fn write_row(
         buffer: &mut String,
         name: &str,
@@ -75,9 +79,9 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
     ) -> std::fmt::Result {
         let TestSuiteRecord { passed, ignored, failed } = record;
         let total = (record.passed + record.ignored + record.failed) as f64;
-        let passed_pct = ((*passed as f64) / total) * 100.0;
-        let ignored_pct = ((*ignored as f64) / total) * 100.0;
-        let failed_pct = ((*failed as f64) / total) * 100.0;
+        let passed_pct = compute_pct(*passed as f64, total) * 100.0;
+        let ignored_pct = compute_pct(*ignored as f64, total) * 100.0;
+        let failed_pct = compute_pct(*failed as f64, total) * 100.0;
 
         write!(buffer, "| {surround}{name}{surround} |")?;
         write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?;
@@ -105,17 +109,21 @@ struct TestSuiteRecord {
     failed: u64,
 }
 
+fn test_metadata_name(metadata: &TestSuiteMetadata) -> String {
+    match metadata {
+        TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
+            format!("{} (stage {stage})", crates.join(", "))
+        }
+        TestSuiteMetadata::Compiletest { suite, stage, .. } => {
+            format!("{suite} (stage {stage})")
+        }
+    }
+}
+
 fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> {
     let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new();
     for suite in suites {
-        let name = match &suite.metadata {
-            TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
-                format!("{} (stage {stage})", crates.join(", "))
-            }
-            TestSuiteMetadata::Compiletest { suite, stage, .. } => {
-                format!("{suite} (stage {stage})")
-            }
-        };
+        let name = test_metadata_name(&suite.metadata);
         let record = records.entry(name).or_default();
         for test in &suite.tests {
             match test.outcome {
@@ -134,7 +142,7 @@ fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRec
     records
 }
 
-fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
+pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
     fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) {
         for node in nodes {
             match node {
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 6b88c26e3a2..eba55338ff8 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -591,7 +591,7 @@ auto:
       RUST_CONFIGURE_ARGS: >-
         --build=i686-pc-windows-msvc
         --host=i686-pc-windows-msvc
-        --target=i686-pc-windows-msvc,i586-pc-windows-msvc
+        --target=i686-pc-windows-msvc
         --enable-full-tools
         --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 2905e470fab..a6996e39822 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -415,6 +415,10 @@ Compiletest directives like `//@ only-<target>` or `//@ ignore-<target>` are
 supported in `rmake.rs`, like in UI tests. However, revisions or building
 auxiliary via directives are not currently supported.
 
+`rmake.rs` and `run-make-support` may *not* use any nightly/unstable features,
+as they must be compilable by a stage 0 rustc that may be a beta or even stable
+rustc.
+
 #### Quickly check if `rmake.rs` tests can be compiled
 
 You can quickly check if `rmake.rs` tests can be compiled without having to
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 84440a5ab78..f78ab151b9c 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -162,7 +162,6 @@ target | std | notes
 [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A
 [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R
 [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat
-`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87]
 `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87]
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87]
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI]
diff --git a/src/doc/unstable-book/src/language-features/default-field-values.md b/src/doc/unstable-book/src/language-features/default-field-values.md
index 3143b2d7cae..6da6c4e6c57 100644
--- a/src/doc/unstable-book/src/language-features/default-field-values.md
+++ b/src/doc/unstable-book/src/language-features/default-field-values.md
@@ -67,7 +67,7 @@ have default field values.
 ## Lints
 
 When manually implementing the `Default` trait for a type that has default
-field values, if any of these are overriden in the impl the
+field values, if any of these are overridden in the impl the
 `default_overrides_default_fields` lint will trigger. This lint is in place
 to avoid surprising diverging behavior between `S { .. }` and
 `S::default()`, where using the same type in both ways could result in
diff --git a/src/doc/unstable-book/src/language-features/rustc-private.md b/src/doc/unstable-book/src/language-features/rustc-private.md
index 3b83a3cf4df..57ed857cdfe 100644
--- a/src/doc/unstable-book/src/language-features/rustc-private.md
+++ b/src/doc/unstable-book/src/language-features/rustc-private.md
@@ -12,3 +12,33 @@ The presence of this feature changes the way the linkage format for dylibs is ca
 that is necessary for linking against dylibs that statically link `std` (such as `rustc_driver`).
 This makes this feature "viral" in linkage; its use in a given crate makes its use required in
 dependent crates which link to it (including integration tests, which are built as separate crates).
+
+## Common linker failures related to missing LLVM libraries
+
+### When using `rustc-private` with Official Toolchains
+
+When using the `rustc_private` feature with official toolchains distributed via rustup, you'll need to install:
+
+1. The `rustc-dev` component (provides compiler libraries)
+2. The `llvm-tools` component (provides LLVM libraries needed for linking)
+
+You can install these components using `rustup`:
+
+```text
+rustup component add rustc-dev llvm-tools
+```
+
+Without the `llvm-tools` component, you may encounter linking errors like:
+
+```text
+error: linking with `cc` failed: exit status: 1
+  |
+  = note: rust-lld: error: unable to find library -lLLVM-{version}
+```
+
+### When using `rustc-private` with Custom Toolchains
+
+For custom-built toolchains or environments not using rustup, different configuration may be required:
+
+- Ensure LLVM libraries are available in your library search paths
+- You might need to configure library paths explicitly depending on your LLVM installation
diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml
index 56cb5cddeea..bacb9e09f3f 100644
--- a/src/etc/test-float-parse/Cargo.toml
+++ b/src/etc/test-float-parse/Cargo.toml
@@ -7,8 +7,8 @@ publish = false
 [dependencies]
 indicatif = { version = "0.17.8", default-features = false }
 num = "0.4.3"
-rand = "0.8.5"
-rand_chacha = "0.3"
+rand = "0.9.0"
+rand_chacha = "0.9.0"
 rayon = "1"
 
 [lib]
diff --git a/src/etc/test-float-parse/src/gen/fuzz.rs b/src/etc/test-float-parse/src/gen/fuzz.rs
index 7fc999d1671..1d6c5562a14 100644
--- a/src/etc/test-float-parse/src/gen/fuzz.rs
+++ b/src/etc/test-float-parse/src/gen/fuzz.rs
@@ -6,7 +6,7 @@ use std::ops::Range;
 use std::sync::Mutex;
 
 use rand::Rng;
-use rand::distributions::{Distribution, Standard};
+use rand::distr::{Distribution, StandardUniform};
 use rand_chacha::ChaCha8Rng;
 use rand_chacha::rand_core::SeedableRng;
 
@@ -47,7 +47,7 @@ impl<F: Float> Fuzz<F> {
 
 impl<F: Float> Generator<F> for Fuzz<F>
 where
-    Standard: Distribution<<F as Float>::Int>,
+    StandardUniform: Distribution<<F as Float>::Int>,
 {
     const SHORT_NAME: &'static str = "fuzz";
 
@@ -74,13 +74,13 @@ where
 
 impl<F: Float> Iterator for Fuzz<F>
 where
-    Standard: Distribution<<F as Float>::Int>,
+    StandardUniform: Distribution<<F as Float>::Int>,
 {
     type Item = <Self as Generator<F>>::WriteCtx;
 
     fn next(&mut self) -> Option<Self::Item> {
         let _ = self.iter.next()?;
-        let i: F::Int = self.rng.gen();
+        let i: F::Int = self.rng.random();
 
         Some(F::from_bits(i))
     }
diff --git a/src/etc/test-float-parse/src/gen/many_digits.rs b/src/etc/test-float-parse/src/gen/many_digits.rs
index aab8d5d704b..741e11437fe 100644
--- a/src/etc/test-float-parse/src/gen/many_digits.rs
+++ b/src/etc/test-float-parse/src/gen/many_digits.rs
@@ -3,7 +3,7 @@ use std::fmt::Write;
 use std::marker::PhantomData;
 use std::ops::{Range, RangeInclusive};
 
-use rand::distributions::{Distribution, Uniform};
+use rand::distr::{Distribution, Uniform};
 use rand::{Rng, SeedableRng};
 use rand_chacha::ChaCha8Rng;
 
@@ -40,7 +40,7 @@ impl<F: Float> Generator<F> for RandDigits<F> {
 
     fn new() -> Self {
         let rng = ChaCha8Rng::from_seed(SEED);
-        let range = Uniform::from(0..10);
+        let range = Uniform::try_from(0..10).unwrap();
 
         Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData }
     }
@@ -55,11 +55,11 @@ impl<F: Float> Iterator for RandDigits<F> {
 
     fn next(&mut self) -> Option<Self::Item> {
         let _ = self.iter.next()?;
-        let num_digits = self.rng.gen_range(POSSIBLE_NUM_DIGITS);
-        let has_decimal = self.rng.gen_bool(0.2);
-        let has_exp = self.rng.gen_bool(0.2);
+        let num_digits = self.rng.random_range(POSSIBLE_NUM_DIGITS);
+        let has_decimal = self.rng.random_bool(0.2);
+        let has_exp = self.rng.random_bool(0.2);
 
-        let dec_pos = if has_decimal { Some(self.rng.gen_range(0..num_digits)) } else { None };
+        let dec_pos = if has_decimal { Some(self.rng.random_range(0..num_digits)) } else { None };
 
         let mut s = String::with_capacity(num_digits);
 
@@ -75,7 +75,7 @@ impl<F: Float> Iterator for RandDigits<F> {
         }
 
         if has_exp {
-            let exp = self.rng.gen_range(EXP_RANGE);
+            let exp = self.rng.random_range(EXP_RANGE);
             write!(s, "e{exp}").unwrap();
         }
 
diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs
index def66398d9f..e2f84b085c6 100644
--- a/src/etc/test-float-parse/src/lib.rs
+++ b/src/etc/test-float-parse/src/lib.rs
@@ -10,7 +10,7 @@ use std::sync::OnceLock;
 use std::sync::atomic::{AtomicU64, Ordering};
 use std::{fmt, time};
 
-use rand::distributions::{Distribution, Standard};
+use rand::distr::{Distribution, StandardUniform};
 use rayon::prelude::*;
 use time::{Duration, Instant};
 use traits::{Float, Generator, Int};
@@ -132,7 +132,7 @@ fn register_float<F: Float>(tests: &mut Vec<TestInfo>, cfg: &Config)
 where
     RangeInclusive<F::Int>: Iterator<Item = F::Int>,
     <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
-    Standard: Distribution<<F as traits::Float>::Int>,
+    StandardUniform: Distribution<<F as traits::Float>::Int>,
 {
     if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE {
         // Only run exhaustive tests if there is a chance of completion.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e10a74221ae..8c6ea00d489 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -563,11 +563,13 @@ pub(crate) fn build_impl(
     // Return if the trait itself or any types of the generic parameters are doc(hidden).
     let mut stack: Vec<&Type> = vec![&for_];
 
-    if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
-        if !document_hidden && tcx.is_doc_hidden(did) {
-            return;
-        }
+    if let Some(did) = trait_.as_ref().map(|t| t.def_id())
+        && !document_hidden
+        && tcx.is_doc_hidden(did)
+    {
+        return;
     }
+
     if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
         stack.extend(generics);
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bb12e4a706e..97ff4c2ef40 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -828,30 +828,26 @@ fn clean_ty_generics<'tcx>(
         .iter()
         .flat_map(|(pred, _)| {
             let mut projection = None;
-            let param_idx = (|| {
+            let param_idx = {
                 let bound_p = pred.kind();
                 match bound_p.skip_binder() {
-                    ty::ClauseKind::Trait(pred) => {
-                        if let ty::Param(param) = pred.self_ty().kind() {
-                            return Some(param.index);
-                        }
+                    ty::ClauseKind::Trait(pred) if let ty::Param(param) = pred.self_ty().kind() => {
+                        Some(param.index)
                     }
-                    ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
-                        if let ty::Param(param) = ty.kind() {
-                            return Some(param.index);
-                        }
+                    ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg))
+                        if let ty::Param(param) = ty.kind() =>
+                    {
+                        Some(param.index)
                     }
-                    ty::ClauseKind::Projection(p) => {
-                        if let ty::Param(param) = p.projection_term.self_ty().kind() {
-                            projection = Some(bound_p.rebind(p));
-                            return Some(param.index);
-                        }
+                    ty::ClauseKind::Projection(p)
+                        if let ty::Param(param) = p.projection_term.self_ty().kind() =>
+                    {
+                        projection = Some(bound_p.rebind(p));
+                        Some(param.index)
                     }
-                    _ => (),
+                    _ => None,
                 }
-
-                None
-            })();
+            };
 
             if let Some(param_idx) = param_idx
                 && let Some(bounds) = impl_trait.get_mut(&param_idx)
@@ -1378,12 +1374,12 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
                     tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
                 if self_arg_ty == self_ty {
                     item.decl.inputs.values[0].type_ = SelfTy;
-                } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
-                    if ty == self_ty {
-                        match item.decl.inputs.values[0].type_ {
-                            BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
-                            _ => unreachable!(),
-                        }
+                } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind()
+                    && ty == self_ty
+                {
+                    match item.decl.inputs.values[0].type_ {
+                        BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
+                        _ => unreachable!(),
                     }
                 }
             }
@@ -2331,25 +2327,22 @@ fn clean_middle_opaque_bounds<'tcx>(
             let bindings: ThinVec<_> = bounds
                 .iter()
                 .filter_map(|(bound, _)| {
-                    if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
-                        if proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() {
-                            Some(AssocItemConstraint {
-                                assoc: projection_to_path_segment(
-                                    // FIXME: This needs to be made resilient for `AliasTerm`s that
-                                    // are associated consts.
-                                    bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)),
-                                    cx,
-                                ),
-                                kind: AssocItemConstraintKind::Equality {
-                                    term: clean_middle_term(bound.kind().rebind(proj.term), cx),
-                                },
-                            })
-                        } else {
-                            None
-                        }
-                    } else {
-                        None
+                    if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder()
+                        && proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
+                    {
+                        return Some(AssocItemConstraint {
+                            assoc: projection_to_path_segment(
+                                // FIXME: This needs to be made resilient for `AliasTerm`s that
+                                // are associated consts.
+                                bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)),
+                                cx,
+                            ),
+                            kind: AssocItemConstraintKind::Equality {
+                                term: clean_middle_term(bound.kind().rebind(proj.term), cx),
+                            },
+                        });
                     }
+                    None
                 })
                 .collect();
 
@@ -2539,7 +2532,7 @@ fn clean_generic_args<'tcx>(
 ) -> GenericArgs {
     // FIXME(return_type_notation): Fix RTN parens rendering
     if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
-        let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect::<ThinVec<_>>().into();
+        let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect();
         let output = match output.kind {
             hir::TyKind::Tup(&[]) => None,
             _ => Some(Box::new(clean_ty(output, cx))),
@@ -2560,8 +2553,7 @@ fn clean_generic_args<'tcx>(
                 }
                 hir::GenericArg::Infer(_inf) => GenericArg::Infer,
             })
-            .collect::<ThinVec<_>>()
-            .into();
+            .collect();
         let constraints = generic_args
             .constraints
             .iter()
@@ -2743,23 +2735,20 @@ fn add_without_unwanted_attributes<'hir>(
         }
         let mut attr = attr.clone();
         match attr {
-            hir::Attribute::Unparsed(ref mut normal) => {
-                if let [ident] = &*normal.path.segments {
-                    let ident = ident.name;
-                    if ident == sym::doc {
-                        filter_doc_attr(&mut normal.args, is_inline);
-                        attrs.push((Cow::Owned(attr), import_parent));
-                    } else if is_inline || ident != sym::cfg {
-                        // If it's not a `cfg()` attribute, we keep it.
-                        attrs.push((Cow::Owned(attr), import_parent));
-                    }
-                }
-            }
-            hir::Attribute::Parsed(..) => {
-                if is_inline {
+            hir::Attribute::Unparsed(ref mut normal) if let [ident] = &*normal.path.segments => {
+                let ident = ident.name;
+                if ident == sym::doc {
+                    filter_doc_attr(&mut normal.args, is_inline);
+                    attrs.push((Cow::Owned(attr), import_parent));
+                } else if is_inline || ident != sym::cfg {
+                    // If it's not a `cfg()` attribute, we keep it.
                     attrs.push((Cow::Owned(attr), import_parent));
                 }
             }
+            hir::Attribute::Parsed(..) if is_inline => {
+                attrs.push((Cow::Owned(attr), import_parent));
+            }
+            _ => {}
         }
     }
 }
@@ -2961,16 +2950,16 @@ fn clean_extern_crate<'tcx>(
         && !cx.is_json_output();
 
     let krate_owner_def_id = krate.owner_id.def_id;
-    if please_inline {
-        if let Some(items) = inline::try_inline(
+    if please_inline
+        && let Some(items) = inline::try_inline(
             cx,
             Res::Def(DefKind::Mod, crate_def_id),
             name,
             Some((attrs, Some(krate_owner_def_id))),
             &mut Default::default(),
-        ) {
-            return items;
-        }
+        )
+    {
+        return items;
     }
 
     vec![Item::from_def_id_and_parts(
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5906a720e0f..9e9cd528834 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -208,11 +208,11 @@ impl ExternalCrate {
                     .get_attrs(def_id, sym::doc)
                     .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
                 for meta in meta_items {
-                    if meta.has_name(sym::keyword) {
-                        if let Some(v) = meta.value_str() {
-                            keyword = Some(v);
-                            break;
-                        }
+                    if meta.has_name(sym::keyword)
+                        && let Some(v) = meta.value_str()
+                    {
+                        keyword = Some(v);
+                        break;
                     }
                 }
                 return keyword.map(|p| (def_id, p));
@@ -1071,16 +1071,14 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
     // treat #[target_feature(enable = "feat")] attributes as if they were
     // #[doc(cfg(target_feature = "feat"))] attributes as well
     for attr in hir_attr_lists(attrs, sym::target_feature) {
-        if attr.has_name(sym::enable) {
-            if attr.value_str().is_some() {
-                // Clone `enable = "feat"`, change to `target_feature = "feat"`.
-                // Unwrap is safe because `value_str` succeeded above.
-                let mut meta = attr.meta_item().unwrap().clone();
-                meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
-
-                if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
-                    cfg &= feat_cfg;
-                }
+        if attr.has_name(sym::enable) && attr.value_str().is_some() {
+            // Clone `enable = "feat"`, change to `target_feature = "feat"`.
+            // Unwrap is safe because `value_str` succeeded above.
+            let mut meta = attr.meta_item().unwrap().clone();
+            meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
+
+            if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
+                cfg &= feat_cfg;
             }
         }
     }
@@ -1160,10 +1158,10 @@ impl Attributes {
                 continue;
             }
 
-            if let Some(items) = attr.meta_item_list() {
-                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) {
-                    return true;
-                }
+            if let Some(items) = attr.meta_item_list()
+                && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
+            {
+                return true;
             }
         }
 
@@ -2419,7 +2417,7 @@ impl ConstantKind {
             ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
                 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
             }
-            ConstantKind::Infer { .. } => "_".to_string(),
+            ConstantKind::Infer => "_".to_string(),
         }
     }
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index a284de5229a..f81db58950c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -223,7 +223,7 @@ fn clean_middle_generic_args_with_constraints<'tcx>(
 
     let args = clean_middle_generic_args(cx, args.map_bound(|args| &args[..]), has_self, did);
 
-    GenericArgs::AngleBracketed { args: args.into(), constraints }
+    GenericArgs::AngleBracketed { args, constraints }
 }
 
 pub(super) fn clean_middle_path<'tcx>(
@@ -394,7 +394,7 @@ pub(crate) fn print_evaluated_const(
 fn format_integer_with_underscore_sep(num: &str) -> String {
     let num_chars: Vec<_> = num.chars().collect();
     let mut num_start_index = if num_chars.first() == Some(&'-') { 1 } else { 0 };
-    let chunk_size = match num[num_start_index..].as_bytes() {
+    let chunk_size = match &num.as_bytes()[num_start_index..] {
         [b'0', b'b' | b'x', ..] => {
             num_start_index += 2;
             4
@@ -524,7 +524,7 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
             | AssocConst
             | Variant
             | Fn
-            | TyAlias { .. }
+            | TyAlias
             | Enum
             | Trait
             | Struct
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index e67fe6c88ea..9cf471733f9 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -645,10 +645,10 @@ impl Options {
 
         let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));
 
-        if let Some(ref p) = extension_css {
-            if !p.is_file() {
-                dcx.fatal("option --extend-css argument must be a file");
-            }
+        if let Some(ref p) = extension_css
+            && !p.is_file()
+        {
+            dcx.fatal("option --extend-css argument must be a file");
         }
 
         let mut themes = Vec::new();
@@ -720,10 +720,10 @@ impl Options {
         }
 
         let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
-        if let Some(ref index_page) = index_page {
-            if !index_page.is_file() {
-                dcx.fatal("option `--index-page` argument must be a file");
-            }
+        if let Some(ref index_page) = index_page
+            && !index_page.is_file()
+        {
+            dcx.fatal("option `--index-page` argument must be a file");
         }
 
         let target = parse_target_triple(early_dcx, matches);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 679921c3269..719f1f978fe 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -154,13 +154,12 @@ pub(crate) fn new_dcx(
         false,
     );
     let emitter: Box<DynEmitter> = match error_format {
-        ErrorOutputType::HumanReadable(kind, color_config) => {
+        ErrorOutputType::HumanReadable { kind, color_config } => {
             let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
                     .sm(source_map.map(|sm| sm as _))
                     .short_message(short)
-                    .teach(unstable_opts.teach)
                     .diagnostic_width(diagnostic_width)
                     .track_diagnostics(unstable_opts.track_diagnostics)
                     .theme(if let HumanReadableErrorType::Unicode = kind {
diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs
index ee8dde013ee..aa0fad26520 100644
--- a/src/librustdoc/display.rs
+++ b/src/librustdoc/display.rs
@@ -22,7 +22,7 @@ where
         let mut iter = self.into_iter();
         let Some(first) = iter.next() else { return Ok(()) };
         first.fmt(f)?;
-        while let Some(item) = iter.next() {
+        for item in iter {
             f.write_str(sep)?;
             item.fmt(f)?;
         }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 4a379b4235f..88af9a7388c 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -96,7 +96,7 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) ->
         .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()];
+    let mut content = vec![];
 
     for cfg in &options.cfgs {
         content.push(format!("--cfg={cfg}"));
@@ -513,12 +513,18 @@ pub(crate) struct RunnableDocTest {
     line: usize,
     edition: Edition,
     no_run: bool,
-    is_multiple_tests: bool,
+    merged_test_code: Option<String>,
 }
 
 impl RunnableDocTest {
-    fn path_for_merged_doctest(&self) -> PathBuf {
-        self.test_opts.outdir.path().join(format!("doctest_{}.rs", self.edition))
+    fn path_for_merged_doctest_bundle(&self) -> PathBuf {
+        self.test_opts.outdir.path().join(format!("doctest_bundle_{}.rs", self.edition))
+    }
+    fn path_for_merged_doctest_runner(&self) -> PathBuf {
+        self.test_opts.outdir.path().join(format!("doctest_runner_{}.rs", self.edition))
+    }
+    fn is_multiple_tests(&self) -> bool {
+        self.merged_test_code.is_some()
     }
 }
 
@@ -537,91 +543,108 @@ fn run_test(
     let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target);
     let output_file = doctest.test_opts.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);
+    // Common arguments used for compiling the doctest runner.
+    // On merged doctests, the compiler is invoked twice: once for the test code itself,
+    // and once for the runner wrapper (which needs to use `#![feature]` on stable).
+    let mut compiler_args = vec![];
 
-    compiler.arg(format!("@{}", doctest.global_opts.args_file.display()));
+    compiler_args.push(format!("@{}", doctest.global_opts.args_file.display()));
 
     if let Some(sysroot) = &rustdoc_options.maybe_sysroot {
-        compiler.arg(format!("--sysroot={}", sysroot.display()));
+        compiler_args.push(format!("--sysroot={}", sysroot.display()));
     }
 
-    compiler.arg("--edition").arg(doctest.edition.to_string());
-    if !doctest.is_multiple_tests {
-        // Setting these environment variables is unneeded if this is a merged doctest.
-        compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path);
-        compiler.env(
-            "UNSTABLE_RUSTDOC_TEST_LINE",
-            format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize),
-        );
-    }
-    compiler.arg("-o").arg(&output_file);
+    compiler_args.extend_from_slice(&["--edition".to_owned(), doctest.edition.to_string()]);
     if langstr.test_harness {
-        compiler.arg("--test");
+        compiler_args.push("--test".to_owned());
     }
     if rustdoc_options.json_unused_externs.is_enabled() && !langstr.compile_fail {
-        compiler.arg("--error-format=json");
-        compiler.arg("--json").arg("unused-externs");
-        compiler.arg("-W").arg("unused_crate_dependencies");
-        compiler.arg("-Z").arg("unstable-options");
+        compiler_args.push("--error-format=json".to_owned());
+        compiler_args.extend_from_slice(&["--json".to_owned(), "unused-externs".to_owned()]);
+        compiler_args.extend_from_slice(&["-W".to_owned(), "unused_crate_dependencies".to_owned()]);
+        compiler_args.extend_from_slice(&["-Z".to_owned(), "unstable-options".to_owned()]);
     }
 
     if doctest.no_run && !langstr.compile_fail && rustdoc_options.persist_doctests.is_none() {
         // FIXME: why does this code check if it *shouldn't* persist doctests
         //        -- shouldn't it be the negation?
-        compiler.arg("--emit=metadata");
+        compiler_args.push("--emit=metadata".to_owned());
     }
-    compiler.arg("--target").arg(match &rustdoc_options.target {
-        TargetTuple::TargetTuple(s) => s,
-        TargetTuple::TargetJson { path_for_rustdoc, .. } => {
-            path_for_rustdoc.to_str().expect("target path must be valid unicode")
-        }
-    });
-    if let ErrorOutputType::HumanReadable(kind, color_config) = rustdoc_options.error_format {
+    compiler_args.extend_from_slice(&[
+        "--target".to_owned(),
+        match &rustdoc_options.target {
+            TargetTuple::TargetTuple(s) => s.clone(),
+            TargetTuple::TargetJson { path_for_rustdoc, .. } => {
+                path_for_rustdoc.to_str().expect("target path must be valid unicode").to_owned()
+            }
+        },
+    ]);
+    if let ErrorOutputType::HumanReadable { kind, color_config } = rustdoc_options.error_format {
         let short = kind.short();
         let unicode = kind == HumanReadableErrorType::Unicode;
 
         if short {
-            compiler.arg("--error-format").arg("short");
+            compiler_args.extend_from_slice(&["--error-format".to_owned(), "short".to_owned()]);
         }
         if unicode {
-            compiler.arg("--error-format").arg("human-unicode");
+            compiler_args
+                .extend_from_slice(&["--error-format".to_owned(), "human-unicode".to_owned()]);
         }
 
         match color_config {
             ColorConfig::Never => {
-                compiler.arg("--color").arg("never");
+                compiler_args.extend_from_slice(&["--color".to_owned(), "never".to_owned()]);
             }
             ColorConfig::Always => {
-                compiler.arg("--color").arg("always");
+                compiler_args.extend_from_slice(&["--color".to_owned(), "always".to_owned()]);
             }
             ColorConfig::Auto => {
-                compiler.arg("--color").arg(if supports_color { "always" } else { "never" });
+                compiler_args.extend_from_slice(&[
+                    "--color".to_owned(),
+                    if supports_color { "always" } else { "never" }.to_owned(),
+                ]);
             }
         }
     }
 
+    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.args(&compiler_args);
+
     // If this is a merged doctest, we need to write it into a file instead of using stdin
     // because if the size of the merged doctests is too big, it'll simply break stdin.
-    if doctest.is_multiple_tests {
+    if doctest.is_multiple_tests() {
         // It makes the compilation failure much faster if it is for a combined doctest.
         compiler.arg("--error-format=short");
-        let input_file = doctest.path_for_merged_doctest();
+        let input_file = doctest.path_for_merged_doctest_bundle();
         if std::fs::write(&input_file, &doctest.full_test_code).is_err() {
             // If we cannot write this file for any reason, we leave. All combined tests will be
             // tested as standalone tests.
             return Err(TestFailure::CompileError);
         }
-        compiler.arg(input_file);
         if !rustdoc_options.nocapture {
             // If `nocapture` is disabled, then we don't display rustc's output when compiling
             // the merged doctests.
             compiler.stderr(Stdio::null());
         }
+        // bundled tests are an rlib, loaded by a separate runner executable
+        compiler
+            .arg("--crate-type=lib")
+            .arg("--out-dir")
+            .arg(doctest.test_opts.outdir.path())
+            .arg(input_file);
     } else {
+        compiler.arg("--crate-type=bin").arg("-o").arg(&output_file);
+        // Setting these environment variables is unneeded if this is a merged doctest.
+        compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path);
+        compiler.env(
+            "UNSTABLE_RUSTDOC_TEST_LINE",
+            format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize),
+        );
         compiler.arg("-");
         compiler.stdin(Stdio::piped());
         compiler.stderr(Stdio::piped());
@@ -630,8 +653,65 @@ fn run_test(
     debug!("compiler invocation for doctest: {compiler:?}");
 
     let mut child = compiler.spawn().expect("Failed to spawn rustc process");
-    let output = if doctest.is_multiple_tests {
+    let output = if let Some(merged_test_code) = &doctest.merged_test_code {
+        // compile-fail tests never get merged, so this should always pass
         let status = child.wait().expect("Failed to wait");
+
+        // the actual test runner is a separate component, built with nightly-only features;
+        // build it now
+        let runner_input_file = doctest.path_for_merged_doctest_runner();
+
+        let mut runner_compiler =
+            wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
+        // the test runner does not contain any user-written code, so this doesn't allow
+        // the user to exploit nightly-only features on stable
+        runner_compiler.env("RUSTC_BOOTSTRAP", "1");
+        runner_compiler.args(compiler_args);
+        runner_compiler.args(&["--crate-type=bin", "-o"]).arg(&output_file);
+        let mut extern_path = std::ffi::OsString::from(format!(
+            "--extern=doctest_bundle_{edition}=",
+            edition = doctest.edition
+        ));
+        for extern_str in &rustdoc_options.extern_strs {
+            if let Some((_cratename, path)) = extern_str.split_once('=') {
+                // Direct dependencies of the tests themselves are
+                // indirect dependencies of the test runner.
+                // They need to be in the library search path.
+                let dir = Path::new(path)
+                    .parent()
+                    .filter(|x| x.components().count() > 0)
+                    .unwrap_or(Path::new("."));
+                runner_compiler.arg("-L").arg(dir);
+            }
+        }
+        let output_bundle_file = doctest
+            .test_opts
+            .outdir
+            .path()
+            .join(format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition));
+        extern_path.push(&output_bundle_file);
+        runner_compiler.arg(extern_path);
+        runner_compiler.arg(&runner_input_file);
+        if std::fs::write(&runner_input_file, &merged_test_code).is_err() {
+            // If we cannot write this file for any reason, we leave. All combined tests will be
+            // tested as standalone tests.
+            return Err(TestFailure::CompileError);
+        }
+        if !rustdoc_options.nocapture {
+            // If `nocapture` is disabled, then we don't display rustc's output when compiling
+            // the merged doctests.
+            runner_compiler.stderr(Stdio::null());
+        }
+        runner_compiler.arg("--error-format=short");
+        debug!("compiler invocation for doctest runner: {runner_compiler:?}");
+
+        let status = if !status.success() {
+            status
+        } else {
+            let mut child_runner = runner_compiler.spawn().expect("Failed to spawn rustc process");
+            child_runner.wait().expect("Failed to wait")
+        };
+
         process::Output { status, stdout: Vec::new(), stderr: Vec::new() }
     } else {
         let stdin = child.stdin.as_mut().expect("Failed to open stdin");
@@ -708,7 +788,7 @@ fn run_test(
         cmd.arg(&output_file);
     } else {
         cmd = Command::new(&output_file);
-        if doctest.is_multiple_tests {
+        if doctest.is_multiple_tests() {
             cmd.env("RUSTDOC_DOCTEST_BIN_PATH", &output_file);
         }
     }
@@ -716,7 +796,7 @@ fn run_test(
         cmd.current_dir(run_directory);
     }
 
-    let result = if doctest.is_multiple_tests || rustdoc_options.nocapture {
+    let result = if doctest.is_multiple_tests() || rustdoc_options.nocapture {
         cmd.status().map(|status| process::Output {
             status,
             stdout: Vec::new(),
@@ -1003,7 +1083,7 @@ fn doctest_run_fn(
         line: scraped_test.line,
         edition: scraped_test.edition(&rustdoc_options),
         no_run: scraped_test.no_run(&rustdoc_options),
-        is_multiple_tests: false,
+        merged_test_code: None,
     };
     let res =
         run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs);
diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs
index 03c8814a4c9..ce362eabfc4 100644
--- a/src/librustdoc/doctest/extracted.rs
+++ b/src/librustdoc/doctest/extracted.rs
@@ -33,7 +33,7 @@ impl ExtractedDocTests {
         opts: &super::GlobalTestOptions,
         options: &RustdocOptions,
     ) {
-        let edition = scraped_test.edition(&options);
+        let edition = scraped_test.edition(options);
 
         let ScrapedDocTest { filename, line, langstr, text, name } = scraped_test;
 
@@ -48,7 +48,7 @@ impl ExtractedDocTests {
         let (full_test_code, size) = doctest.generate_unique_doctest(
             &text,
             langstr.test_harness,
-            &opts,
+            opts,
             Some(&opts.crate_name),
         );
         self.doctests.push(ExtractedDocTest {
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index 234f40c6c1a..f891505d2a6 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -14,6 +14,7 @@ pub(crate) struct DocTestRunner {
     crate_attrs: FxIndexSet<String>,
     ids: String,
     output: String,
+    output_merged_tests: String,
     supports_color: bool,
     nb_tests: usize,
 }
@@ -24,6 +25,7 @@ impl DocTestRunner {
             crate_attrs: FxIndexSet::default(),
             ids: String::new(),
             output: String::new(),
+            output_merged_tests: String::new(),
             supports_color: true,
             nb_tests: 0,
         }
@@ -45,17 +47,15 @@ impl DocTestRunner {
                 self.crate_attrs.insert(line.to_string());
             }
         }
-        if !self.ids.is_empty() {
-            self.ids.push(',');
-        }
         self.ids.push_str(&format!(
-            "{}::TEST",
+            "tests.push({}::TEST);\n",
             generate_mergeable_doctest(
                 doctest,
                 scraped_test,
                 ignore,
                 self.nb_tests,
-                &mut self.output
+                &mut self.output,
+                &mut self.output_merged_tests,
             ),
         ));
         self.supports_color &= doctest.supports_color;
@@ -78,9 +78,11 @@ impl DocTestRunner {
 "
         .to_string();
 
+        let mut code_prefix = String::new();
+
         for crate_attr in &self.crate_attrs {
-            code.push_str(crate_attr);
-            code.push('\n');
+            code_prefix.push_str(crate_attr);
+            code_prefix.push('\n');
         }
 
         if opts.attrs.is_empty() {
@@ -88,15 +90,16 @@ impl DocTestRunner {
             // lints that are commonly triggered in doctests. The crate-level test attributes are
             // commonly used to make tests fail in case they trigger warnings, so having this there in
             // that case may cause some tests to pass when they shouldn't have.
-            code.push_str("#![allow(unused)]\n");
+            code_prefix.push_str("#![allow(unused)]\n");
         }
 
         // Next, any attributes that came from the crate root via #![doc(test(attr(...)))].
         for attr in &opts.attrs {
-            code.push_str(&format!("#![{attr}]\n"));
+            code_prefix.push_str(&format!("#![{attr}]\n"));
         }
 
         code.push_str("extern crate test;\n");
+        writeln!(code, "extern crate doctest_bundle_{edition} as doctest_bundle;").unwrap();
 
         let test_args = test_args.iter().fold(String::new(), |mut x, arg| {
             write!(x, "{arg:?}.to_string(),").unwrap();
@@ -136,7 +139,11 @@ mod __doctest_mod {{
 
 #[rustc_main]
 fn main() -> std::process::ExitCode {{
-const TESTS: [test::TestDescAndFn; {nb_tests}] = [{ids}];
+let tests = {{
+    let mut tests = Vec::with_capacity({nb_tests});
+    {ids}
+    tests
+}};
 let test_marker = std::ffi::OsStr::new(__doctest_mod::RUN_OPTION);
 let test_args = &[{test_args}];
 const ENV_BIN: &'static str = \"RUSTDOC_DOCTEST_BIN_PATH\";
@@ -144,11 +151,11 @@ const ENV_BIN: &'static str = \"RUSTDOC_DOCTEST_BIN_PATH\";
 if let Ok(binary) = std::env::var(ENV_BIN) {{
     let _ = crate::__doctest_mod::BINARY_PATH.set(binary.into());
     unsafe {{ std::env::remove_var(ENV_BIN); }}
-    return std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), None));
+    return std::process::Termination::report(test::test_main(test_args, tests, None));
 }} else if let Ok(nb_test) = std::env::var(__doctest_mod::RUN_OPTION) {{
     if let Ok(nb_test) = nb_test.parse::<usize>() {{
-        if let Some(test) = TESTS.get(nb_test) {{
-            if let test::StaticTestFn(f) = test.testfn {{
+        if let Some(test) = tests.get(nb_test) {{
+            if let test::StaticTestFn(f) = &test.testfn {{
                 return std::process::Termination::report(f());
             }}
         }}
@@ -158,15 +165,15 @@ if let Ok(binary) = std::env::var(ENV_BIN) {{
 
 eprintln!(\"WARNING: No rustdoc doctest environment variable provided so doctests will be run in \
 the same process\");
-std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), None))
+std::process::Termination::report(test::test_main(test_args, tests, None))
 }}",
             nb_tests = self.nb_tests,
-            output = self.output,
+            output = self.output_merged_tests,
             ids = self.ids,
         )
         .expect("failed to generate test code");
         let runnable_test = RunnableDocTest {
-            full_test_code: code,
+            full_test_code: format!("{code_prefix}{code}", code = self.output),
             full_test_line_offset: 0,
             test_opts: test_options,
             global_opts: opts.clone(),
@@ -174,7 +181,7 @@ std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), N
             line: 0,
             edition,
             no_run: false,
-            is_multiple_tests: true,
+            merged_test_code: Some(code),
         };
         let ret =
             run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {});
@@ -189,14 +196,15 @@ fn generate_mergeable_doctest(
     ignore: bool,
     id: usize,
     output: &mut String,
+    output_merged_tests: &mut String,
 ) -> String {
     let test_id = format!("__doctest_{id}");
 
     if ignore {
         // We generate nothing else.
-        writeln!(output, "mod {test_id} {{\n").unwrap();
+        writeln!(output, "pub mod {test_id} {{}}\n").unwrap();
     } else {
-        writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs)
+        writeln!(output, "pub mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs)
             .unwrap();
         if doctest.has_main_fn {
             output.push_str(&doctest.everything_else);
@@ -216,11 +224,17 @@ fn main() {returns_result} {{
             )
             .unwrap();
         }
+        writeln!(
+            output,
+            "\npub fn __main_fn() -> impl std::process::Termination {{ main() }} \n}}\n"
+        )
+        .unwrap();
     }
     let not_running = ignore || scraped_test.langstr.no_run;
     writeln!(
-        output,
+        output_merged_tests,
         "
+mod {test_id} {{
 pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest(
 {test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic},
 test::StaticTestFn(
@@ -242,7 +256,7 @@ test::StaticTestFn(
 if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{
     test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}))
 }} else {{
-    test::assert_test_result(self::main())
+    test::assert_test_result(doctest_bundle::{test_id}::__main_fn())
 }}
 ",
             )
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index 3ac7abd0aa5..907e2a3eb2f 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -98,10 +98,9 @@ impl HirCollector<'_> {
         let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id));
         if let Some(ref cfg) =
             extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
+            && !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features()))
         {
-            if !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) {
-                return;
-            }
+            return;
         }
 
         let has_name = !name.is_empty();
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 4760e579199..2648641e53e 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -419,7 +419,9 @@ impl DocFolder for CacheBuilder<'_, '_> {
                 }
             }
 
-            if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
+            if let Some(trait_) = &i.trait_
+                && let Some(generics) = trait_.generics()
+            {
                 for bound in generics {
                     dids.extend(bound.def_id(self.cache));
                 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index ea740508c58..8b8439a2535 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -623,10 +623,9 @@ pub(crate) fn href_relative_parts<'fqp>(
         // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
         if f != r {
             let dissimilar_part_count = relative_to_fqp.len() - i;
-            let fqp_module = &fqp[i..fqp.len()];
+            let fqp_module = &fqp[i..];
             return Box::new(
-                iter::repeat(sym::dotdot)
-                    .take(dissimilar_part_count)
+                iter::repeat_n(sym::dotdot, dissimilar_part_count)
                     .chain(fqp_module.iter().copied()),
             );
         }
@@ -639,7 +638,7 @@ pub(crate) fn href_relative_parts<'fqp>(
         Ordering::Greater => {
             // e.g. linking to std::sync from std::sync::atomic
             let dissimilar_part_count = relative_to_fqp.len() - fqp.len();
-            Box::new(iter::repeat(sym::dotdot).take(dissimilar_part_count))
+            Box::new(iter::repeat_n(sym::dotdot, dissimilar_part_count))
         }
         Ordering::Equal => {
             // linking to the same module
@@ -770,10 +769,9 @@ fn primitive_link_fragment(
                     ExternalLocation::Local => {
                         let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
                         Some(if cx.current.first() == Some(&cname_sym) {
-                            iter::repeat(sym::dotdot).take(cx.current.len() - 1).collect()
+                            iter::repeat_n(sym::dotdot, cx.current.len() - 1).collect()
                         } else {
-                            iter::repeat(sym::dotdot)
-                                .take(cx.current.len())
+                            iter::repeat_n(sym::dotdot, cx.current.len())
                                 .chain(iter::once(cname_sym))
                                 .collect()
                         })
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index ed4b97d3625..c943d3ad4d0 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -100,7 +100,7 @@ fn write_header(
     }
 
     if let Some(extra) = extra_content {
-        out.push_str(&extra);
+        out.push_str(extra);
     }
     if class.is_empty() {
         write_str(
@@ -131,7 +131,7 @@ fn write_header(
 /// * If the other `Class` is unclassified and only contains white characters (backline,
 ///   whitespace, etc), it can be merged.
 /// * `Class::Ident` is considered the same as unclassified (because it doesn't have an associated
-///    CSS class).
+///   CSS class).
 fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
     match (class1, class2) {
         (Some(c1), Some(c2)) => c1.is_equal_to(c2),
@@ -233,7 +233,7 @@ impl<F: Write> TokenHandler<'_, '_, F> {
 
     #[inline]
     fn write_line_number(&mut self, line: u32, extra: &'static str) {
-        (self.write_line_number)(&mut self.out, line, extra);
+        (self.write_line_number)(self.out, line, extra);
     }
 }
 
@@ -610,7 +610,7 @@ impl Decorations {
         let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
             .0
             .iter()
-            .flat_map(|(&kind, ranges)| ranges.into_iter().map(move |&(lo, hi)| ((lo, kind), hi)))
+            .flat_map(|(&kind, ranges)| ranges.iter().map(move |&(lo, hi)| ((lo, kind), hi)))
             .unzip();
 
         // Sort the sequences in document order.
@@ -1102,53 +1102,52 @@ fn string_without_closing_tag<T: Display>(
         });
     }
 
-    if let Some(href_context) = href_context {
-        if let Some(href) =
-            href_context.context.shared.span_correspondence_map.get(&def_span).and_then(|href| {
-                let context = href_context.context;
-                // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
-                // one to the documentation page and one to the source definition.
-                // FIXME: currently, external items only generate a link to their documentation,
-                // a link to their definition can be generated using this:
-                // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
-                match href {
-                    LinkFromSrc::Local(span) => {
-                        context.href_from_span_relative(*span, &href_context.current_href)
-                    }
-                    LinkFromSrc::External(def_id) => {
-                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                            .ok()
-                            .map(|(url, _, _)| url)
-                    }
-                    LinkFromSrc::Primitive(prim) => format::href_with_root_path(
-                        PrimitiveType::primitive_locations(context.tcx())[prim],
-                        context,
-                        Some(href_context.root_path),
-                    )
-                    .ok()
-                    .map(|(url, _, _)| url),
-                    LinkFromSrc::Doc(def_id) => {
-                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                            .ok()
-                            .map(|(doc_link, _, _)| doc_link)
-                    }
+    if let Some(href_context) = href_context
+        && let Some(href) = href_context.context.shared.span_correspondence_map.get(&def_span)
+        && let Some(href) = {
+            let context = href_context.context;
+            // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
+            // one to the documentation page and one to the source definition.
+            // FIXME: currently, external items only generate a link to their documentation,
+            // a link to their definition can be generated using this:
+            // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
+            match href {
+                LinkFromSrc::Local(span) => {
+                    context.href_from_span_relative(*span, &href_context.current_href)
                 }
-            })
-        {
-            if !open_tag {
-                // We're already inside an element which has the same klass, no need to give it
-                // again.
+                LinkFromSrc::External(def_id) => {
+                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                        .ok()
+                        .map(|(url, _, _)| url)
+                }
+                LinkFromSrc::Primitive(prim) => format::href_with_root_path(
+                    PrimitiveType::primitive_locations(context.tcx())[prim],
+                    context,
+                    Some(href_context.root_path),
+                )
+                .ok()
+                .map(|(url, _, _)| url),
+                LinkFromSrc::Doc(def_id) => {
+                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                        .ok()
+                        .map(|(doc_link, _, _)| doc_link)
+                }
+            }
+        }
+    {
+        if !open_tag {
+            // We're already inside an element which has the same klass, no need to give it
+            // again.
+            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+        } else {
+            let klass_s = klass.as_html();
+            if klass_s.is_empty() {
                 write!(out, "<a href=\"{href}\">{text_s}").unwrap();
             } else {
-                let klass_s = klass.as_html();
-                if klass_s.is_empty() {
-                    write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-                } else {
-                    write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
-                }
+                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
             }
-            return Some("</a>");
         }
+        return Some("</a>");
     }
     if !open_tag {
         write!(out, "{}", text_s).unwrap();
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index d9e49577d39..079651e8603 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1308,18 +1308,17 @@ impl LangString {
                         seen_other_tags = true;
                         data.unknown.push(x.to_owned());
                     }
-                    LangStringToken::KeyValueAttribute(key, value) => {
-                        if key == "class" {
-                            data.added_classes.push(value.to_owned());
-                        } else if let Some(extra) = extra {
-                            extra.error_invalid_codeblock_attr(format!(
-                                "unsupported attribute `{key}`"
-                            ));
-                        }
+                    LangStringToken::KeyValueAttribute("class", value) => {
+                        data.added_classes.push(value.to_owned());
+                    }
+                    LangStringToken::KeyValueAttribute(key, ..) if let Some(extra) = extra => {
+                        extra
+                            .error_invalid_codeblock_attr(format!("unsupported attribute `{key}`"));
                     }
                     LangStringToken::ClassAttribute(class) => {
                         data.added_classes.push(class.to_owned());
                     }
+                    _ => {}
                 }
             }
         };
@@ -1792,7 +1791,7 @@ pub(crate) fn markdown_links<'md, R>(
                     }
                 }
             } else if !c.is_ascii_whitespace() {
-                while let Some((j, c)) = iter.next() {
+                for (j, c) in iter.by_ref() {
                     if c.is_ascii_whitespace() {
                         return MarkdownLinkRange::Destination(i + span.start..j + span.start);
                     }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c599a84ee44..3c5c2ce1976 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1,6 +1,6 @@
 use std::cmp::Ordering;
-use std::fmt;
-use std::fmt::{Display, Write as _};
+use std::fmt::{self, Display, Write as _};
+use std::iter;
 
 use rinja::Template;
 use rustc_abi::VariantIdx;
@@ -1192,10 +1192,8 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt:
         // to already be in the HTML, and will be ignored.
         //
         // [JSONP]: https://en.wikipedia.org/wiki/JSONP
-        let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
-            .take(cx.current.len())
-            .chain(std::iter::once("trait.impl"))
-            .collect();
+        let mut js_src_path: UrlPartsBuilder =
+            iter::repeat_n("..", cx.current.len()).chain(iter::once("trait.impl")).collect();
         if let Some(did) = it.item_id.as_def_id()
             && let get_extern = { || cx.shared.cache.external_paths.get(&did).map(|s| &s.0) }
             && let Some(fqp) = cx.shared.cache.exact_paths.get(&did).or_else(get_extern)
@@ -1446,10 +1444,8 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) ->
             && let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) }
             && let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local)
         {
-            let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
-                .take(cx.current.len())
-                .chain(std::iter::once("type.impl"))
-                .collect();
+            let mut js_src_path: UrlPartsBuilder =
+                iter::repeat_n("..", cx.current.len()).chain(iter::once("type.impl")).collect();
             js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
             js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
             let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f));
@@ -1493,7 +1489,7 @@ fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt:
 
         fn fields_iter(
             &self,
-        ) -> std::iter::Peekable<impl Iterator<Item = (&'a clean::Item, &'a clean::Type)>> {
+        ) -> iter::Peekable<impl Iterator<Item = (&'a clean::Item, &'a clean::Type)>> {
             self.s
                 .fields
                 .iter()
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 95f617c9839..b39701fae1d 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -842,10 +842,7 @@ pub(crate) fn get_function_type_for_search(
         }
         clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
         clean::StaticItem(ref s) => make_nullary_fn(&s.type_),
-        clean::StructFieldItem(ref t) => {
-            let Some(parent) = parent else {
-                return None;
-            };
+        clean::StructFieldItem(ref t) if let Some(parent) = parent => {
             let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> =
                 Default::default();
             let output = get_index_type(t, vec![], &mut rgen);
diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs
index 8816ea65059..de2f54558ff 100644
--- a/src/librustdoc/html/render/search_index/encode.rs
+++ b/src/librustdoc/html/render/search_index/encode.rs
@@ -182,9 +182,9 @@ pub(crate) fn write_bitmap_to_bytes(
             out.write_all(&[b])?;
         }
         if size < NO_OFFSET_THRESHOLD {
-            4 + 4 * size + ((size + 7) / 8)
+            4 + 4 * size + size.div_ceil(8)
         } else {
-            4 + 8 * size + ((size + 7) / 8)
+            4 + 8 * size + size.div_ceil(8)
         }
     } else {
         out.write_all(&u32::to_le_bytes(SERIAL_COOKIE_NO_RUNCONTAINER))?;
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 64dbaf9083e..3130815af0b 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -79,7 +79,7 @@ impl<'a> LinkBlock<'a> {
 }
 
 /// A link to an item. Content should not be escaped.
-#[derive(Ord, PartialEq, Eq, Hash, Clone)]
+#[derive(PartialEq, Eq, Hash, Clone)]
 pub(crate) struct Link<'a> {
     /// The content for the anchor tag and title attr
     name: Cow<'a, str>,
@@ -91,13 +91,13 @@ pub(crate) struct Link<'a> {
     children: Vec<Link<'a>>,
 }
 
-impl PartialOrd for Link<'_> {
-    fn partial_cmp(&self, other: &Link<'_>) -> Option<Ordering> {
+impl Ord for Link<'_> {
+    fn cmp(&self, other: &Self) -> Ordering {
         match compare_names(&self.name, &other.name) {
-            Ordering::Equal => (),
-            result => return Some(result),
+            Ordering::Equal => {}
+            result => return result,
         }
-        (&self.name_html, &self.href, &self.children).partial_cmp(&(
+        (&self.name_html, &self.href, &self.children).cmp(&(
             &other.name_html,
             &other.href,
             &other.children,
@@ -105,6 +105,12 @@ impl PartialOrd for Link<'_> {
     }
 }
 
+impl PartialOrd for Link<'_> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
 impl<'a> Link<'a> {
     pub fn new(href: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> Self {
         Self { href: href.into(), name: name.into(), children: vec![], name_html: None }
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index ce9c42c01cc..4610e092cdf 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -95,10 +95,8 @@ impl SpanMapVisitor<'_> {
                     .unwrap_or(path.span);
                 self.matches.insert(span, link);
             }
-            Res::Local(_) => {
-                if let Some(span) = self.tcx.hir().res_span(path.res) {
-                    self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
-                }
+            Res::Local(_) if let Some(span) = self.tcx.hir().res_span(path.res) => {
+                self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
@@ -111,15 +109,15 @@ impl SpanMapVisitor<'_> {
 
     /// Used to generate links on items' definition to go to their documentation page.
     pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) {
-        if let Node::Item(item) = self.tcx.hir_node(hir_id) {
-            if let Some(span) = self.tcx.def_ident_span(item.owner_id) {
-                let cspan = clean::Span::new(span);
-                // If the span isn't from the current crate, we ignore it.
-                if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
-                    return;
-                }
-                self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
+        if let Node::Item(item) = self.tcx.hir_node(hir_id)
+            && let Some(span) = self.tcx.def_ident_span(item.owner_id)
+        {
+            let cspan = clean::Span::new(span);
+            // If the span isn't from the current crate, we ignore it.
+            if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
+                return;
             }
+            self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
         }
     }
 
@@ -253,7 +251,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             // If it's a "mod foo {}", we want to look to its documentation page.
             self.extract_info_from_hir_id(id);
         }
-        intravisit::walk_mod(self, m, id);
+        intravisit::walk_mod(self, m);
     }
 
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 440d6331457..fdbb792d25d 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1334,14 +1334,12 @@ impl LinkCollector<'_, '_> {
             }
 
         // item can be non-local e.g. when using `#[rustc_doc_primitive = "pointer"]`
-        if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| {
-            diag_info.item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
-        }) {
-            if self.cx.tcx.effective_visibilities(()).is_exported(src_id)
-                && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
-            {
-                privacy_error(self.cx, diag_info, path_str);
-            }
+        if let Some(dst_id) = id.as_local()
+            && let Some(src_id) = diag_info.item.item_id.expect_def_id().as_local()
+            && self.cx.tcx.effective_visibilities(()).is_exported(src_id)
+            && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
+        {
+            privacy_error(self.cx, diag_info, path_str);
         }
 
         Some(())
@@ -1405,10 +1403,10 @@ impl LinkCollector<'_, '_> {
         // which we want in some cases but not in others.
         cache_errors: bool,
     ) -> Option<Vec<(Res, Option<UrlFragment>)>> {
-        if let Some(res) = self.visited_links.get(&key) {
-            if res.is_some() || cache_errors {
-                return res.clone().map(|r| vec![r]);
-            }
+        if let Some(res) = self.visited_links.get(&key)
+            && (res.is_some() || cache_errors)
+        {
+            return res.clone().map(|r| vec![r]);
         }
 
         let mut candidates = self.resolve_with_disambiguator(&key, diag.clone());
@@ -1432,10 +1430,10 @@ impl LinkCollector<'_, '_> {
         // and after removing duplicated kinds, only one remains, the `ambiguity_error` function
         // won't emit an error. So at this point, we can just take the first candidate as it was
         // the first retrieved and use it to generate the link.
-        if let [candidate, _candidate2, ..] = *candidates {
-            if !ambiguity_error(self.cx, &diag, &key.path_str, &candidates, false) {
-                candidates = vec![candidate];
-            }
+        if let [candidate, _candidate2, ..] = *candidates
+            && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates, false)
+        {
+            candidates = vec![candidate];
         }
 
         let mut out = Vec::with_capacity(candidates.len());
@@ -1480,17 +1478,16 @@ impl LinkCollector<'_, '_> {
                         // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach.
                         let mut err = ResolutionFailure::NotResolved(err);
                         for other_ns in [TypeNS, ValueNS, MacroNS] {
-                            if other_ns != expected_ns {
-                                if let Ok(&[res, ..]) = self
+                            if other_ns != expected_ns
+                                && let Ok(&[res, ..]) = self
                                     .resolve(path_str, other_ns, None, item_id, module_id)
                                     .as_deref()
-                                {
-                                    err = ResolutionFailure::WrongNamespace {
-                                        res: full_res(self.cx.tcx, res),
-                                        expected_ns,
-                                    };
-                                    break;
-                                }
+                            {
+                                err = ResolutionFailure::WrongNamespace {
+                                    res: full_res(self.cx.tcx, res),
+                                    expected_ns,
+                                };
+                                break;
                             }
                         }
                         resolution_failure(self, diag, path_str, disambiguator, smallvec![err]);
@@ -1674,11 +1671,11 @@ impl Disambiguator {
             Ok(Some((d, &rest[1..], &rest[1..])))
         } else {
             for (suffix, kind) in suffixes {
-                if let Some(path_str) = link.strip_suffix(suffix) {
-                    // Avoid turning `!` or `()` into an empty string
-                    if !path_str.is_empty() {
-                        return Ok(Some((Kind(kind), path_str, link)));
-                    }
+                // Avoid turning `!` or `()` into an empty string
+                if let Some(path_str) = link.strip_suffix(suffix)
+                    && !path_str.is_empty()
+                {
+                    return Ok(Some((Kind(kind), path_str, link)));
                 }
             }
             Ok(None)
@@ -2060,7 +2057,7 @@ fn resolution_failure(
                                 return;
                             }
                             Trait
-                            | TyAlias { .. }
+                            | TyAlias
                             | ForeignTy
                             | OpaqueTy
                             | TraitAlias
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 87f85c57315..f4e4cd924f7 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -177,23 +177,22 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
             } else if let Some(did) = target.def_id(&cx.cache) {
                 cleaner.items.insert(did.into());
             }
-            if let Some(for_did) = for_.def_id(&cx.cache) {
-                if type_did_to_deref_target.insert(for_did, target).is_none() {
-                    // Since only the `DefId` portion of the `Type` instances is known to be same for both the
-                    // `Deref` target type and the impl for type positions, this map of types is keyed by
-                    // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
-                    if cleaner.keep_impl_with_def_id(for_did.into()) {
-                        let mut targets = DefIdSet::default();
-                        targets.insert(for_did);
-                        add_deref_target(
-                            cx,
-                            &type_did_to_deref_target,
-                            &mut cleaner,
-                            &mut targets,
-                            for_did,
-                        );
-                    }
-                }
+            if let Some(for_did) = for_.def_id(&cx.cache)
+                && type_did_to_deref_target.insert(for_did, target).is_none()
+                // Since only the `DefId` portion of the `Type` instances is known to be same for both the
+                // `Deref` target type and the impl for type positions, this map of types is keyed by
+                // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
+                && cleaner.keep_impl_with_def_id(for_did.into())
+            {
+                let mut targets = DefIdSet::default();
+                targets.insert(for_did);
+                add_deref_target(
+                    cx,
+                    &type_did_to_deref_target,
+                    &mut cleaner,
+                    &mut targets,
+                    for_did,
+                );
             }
         }
     }
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index 3fb154dc515..b9739726c95 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -28,9 +28,9 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
             // We don't try to detect stuff `<like, this>` because that's not valid HTML,
             // and we don't try to detect stuff `<like this>` because that's not valid Rust.
             let mut generics_end = range.end;
-            if let Some(Some(mut generics_start)) = (is_open_tag
-                && dox[..generics_end].ends_with('>'))
-            .then(|| extract_path_backwards(dox, range.start))
+            if is_open_tag
+                && dox[..generics_end].ends_with('>')
+                && let Some(mut generics_start) = extract_path_backwards(dox, range.start)
             {
                 while generics_start != 0
                     && generics_end < dox.len()
diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs
index a3c3134f4c2..95646413a2d 100644
--- a/src/librustdoc/passes/lint/unportable_markdown.rs
+++ b/src/librustdoc/passes/lint/unportable_markdown.rs
@@ -73,15 +73,15 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
         }
         let parser_old = cmarko::Parser::new_ext(dox, main_body_opts_old()).into_offset_iter();
         for (event, span) in parser_old {
-            if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event {
-                if !dox[span.clone()].starts_with("> ") {
-                    spaceless_block_quotes.remove(&span.start);
-                }
+            if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event
+                && !dox[span.clone()].starts_with("> ")
+            {
+                spaceless_block_quotes.remove(&span.start);
             }
-            if let cmarko::Event::FootnoteReference(_) = event {
-                if !found_footnote_references.contains(&(span.start + 1)) {
-                    missing_footnote_references.insert(span.start + 1, span);
-                }
+            if let cmarko::Event::FootnoteReference(_) = event
+                && !found_footnote_references.contains(&(span.start + 1))
+            {
+                missing_footnote_references.insert(span.start + 1, span);
             }
         }
     }
diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs
index 8cf39afd55c..fdab2b08779 100644
--- a/src/librustdoc/passes/propagate_stability.rs
+++ b/src/librustdoc/passes/propagate_stability.rs
@@ -39,15 +39,15 @@ impl DocFolder for StabilityPropagator<'_, '_> {
                 let item_stability = self.cx.tcx.lookup_stability(def_id);
                 let inline_stability =
                     item.inline_stmt_id.and_then(|did| self.cx.tcx.lookup_stability(did));
-                let is_glob_export = item.inline_stmt_id.and_then(|id| {
+                let is_glob_export = item.inline_stmt_id.map(|id| {
                     let hir_id = self.cx.tcx.local_def_id_to_hir_id(id);
-                    Some(matches!(
+                    matches!(
                         self.cx.tcx.hir_node(hir_id),
                         rustc_hir::Node::Item(rustc_hir::Item {
                             kind: rustc_hir::ItemKind::Use(_, rustc_hir::UseKind::Glob),
                             ..
                         })
-                    ))
+                    )
                 });
                 let own_stability = if let Some(item_stab) = item_stability
                     && let StabilityLevel::Stable { since: _, allowed_through_unstable_modules } =
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 3e66ed9f56d..369fc52860e 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -57,10 +57,10 @@ impl LibEmbargoVisitor<'_, '_> {
         }
 
         for item in self.tcx.module_children(def_id).iter() {
-            if let Some(def_id) = item.res.opt_def_id() {
-                if item.vis.is_public() {
-                    self.visit_item(def_id);
-                }
+            if let Some(def_id) = item.res.opt_def_id()
+                && item.vis.is_public()
+            {
+                self.visit_item(def_id);
             }
         }
     }
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index cd5ca74f8ad..dfc8f3bc7e0 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -97,7 +97,6 @@ static TARGETS: &[&str] = &[
     "bpfeb-unknown-none",
     "bpfel-unknown-none",
     "i386-apple-ios",
-    "i586-pc-windows-msvc",
     "i586-unknown-linux-gnu",
     "i586-unknown-linux-musl",
     "i586-unknown-redox",
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 2622e844bc1e2e6123e54e94e4706f7b6195ce3
+Subproject ab1463d632528e39daf35f263e10c14cbe590ce
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 8d1e893cb1a..33ba401d60c 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -150,6 +150,8 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> {
         }
     }
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
         if cmt.place.projections.is_empty() {
             if let PlaceBase::Local(lid) = cmt.place.base {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 39e5e140b7a..fb5d49a1004 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -79,6 +79,8 @@ struct MutatePairDelegate<'a, 'tcx> {
 impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
         if bk == ty::BorrowKind::Mutable {
             if let PlaceBase::Local(id) = cmt.place.base {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index b679fdfadc3..dd7a6f77acf 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -160,6 +160,7 @@ fn never_loop_expr<'tcx>(
         | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id),
         ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
         ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
+        ExprKind::Use(expr, _) => never_loop_expr(cx, expr, local_labels, main_loop_id),
         ExprKind::MethodCall(_, receiver, es, _) => {
             never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id)
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 09440c396ee..d0905733ab5 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -99,7 +99,7 @@ where
                 });
                 if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
                     match captures.get(l) {
-                        Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+                        Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None,
                         Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
                             return None;
                         },
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index a80977459f2..f51bdc78f8a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -147,6 +147,8 @@ impl<'tcx> Delegate<'tcx> for MoveDelegate {
         }
     }
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {}
 
     fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index d5c5679c990..dc10de24bc8 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -396,6 +396,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
         }
     }
 
+    fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
+
     #[allow(clippy::if_same_then_else)]
     fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) {
         self.prev_bind = None;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 380cc380ad0..dc85176ebb9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -326,6 +326,8 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
         self.move_common(cmt);
     }
 
+    fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {}
 
     fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 5737a91031d..03b907ebdf4 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -112,6 +112,7 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet {
         }
 
         fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
+        fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {}
         fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
@@ -137,6 +138,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet {
         }
 
         fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
+        fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {}
         fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index de9f055863c..75b18bc651e 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -177,7 +177,7 @@ fn try_get_option_occurrence<'tcx>(
                         .then_some(())
                         .and_then(|()| none_captures.get(local_id))
                 }) {
-                    Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+                    Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None,
                     Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
                     Some(CaptureKind::Ref(Mutability::Not)) | None => (),
                 }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 76b9bbbd32f..6f6683eb971 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -230,6 +230,8 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
 
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 5fc166438e8..9d8c161873c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -426,6 +426,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Tup({elements})");
                 self.slice(elements, |e| self.expr(e));
             },
+            ExprKind::Use(expr, _) => {
+                bind!(self, expr);
+                kind!("Use({expr})");
+                self.expr(expr);
+            },
             ExprKind::Binary(op, left, right) => {
                 bind!(self, op, left, right);
                 kind!("Binary({op}, {left}, {right})");
@@ -488,6 +493,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             }) => {
                 let capture_clause = match capture_clause {
                     CaptureBy::Value { .. } => "Value { .. }",
+                    CaptureBy::Use { .. } => "Use { .. }",
                     CaptureBy::Ref => "Ref",
                 };
 
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index aaea8d71efb..4543a20cc2c 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -291,6 +291,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::ConstBlock(_)
                 | ExprKind::Array(_)
                 | ExprKind::Tup(_)
+                | ExprKind::Use(..)
                 | ExprKind::Lit(_)
                 | ExprKind::Cast(..)
                 | ExprKind::Type(..)
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index c47c08285c2..9938e64d242 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -393,6 +393,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
             },
             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
+            (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr),
             (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt),
             (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re),
@@ -425,6 +426,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 | &ExprKind::Ret(..)
                 | &ExprKind::Struct(..)
                 | &ExprKind::Tup(..)
+                | &ExprKind::Use(..)
                 | &ExprKind::Type(..)
                 | &ExprKind::Unary(..)
                 | &ExprKind::Yield(..)
@@ -1053,6 +1055,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Tup(tup) => {
                 self.hash_exprs(tup);
             },
+            ExprKind::Use(expr, _) => {
+                self.hash_expr(expr);
+            },
             ExprKind::Unary(lop, le) => {
                 std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index d850cc41000..d8969246844 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1129,6 +1129,7 @@ pub fn can_move_expr_to_closure_no_visit<'tcx>(
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum CaptureKind {
     Value,
+    Use,
     Ref(Mutability),
 }
 impl CaptureKind {
@@ -1141,6 +1142,7 @@ impl std::ops::BitOr for CaptureKind {
     fn bitor(self, rhs: Self) -> Self::Output {
         match (self, rhs) {
             (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
+            (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use,
             (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
             | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
             (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
@@ -1220,7 +1222,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                 },
                 ExprKind::Let(let_expr) => {
                     let mutability = match pat_capture_kind(cx, let_expr.pat) {
-                        CaptureKind::Value => Mutability::Not,
+                        CaptureKind::Value | CaptureKind::Use => Mutability::Not,
                         CaptureKind::Ref(m) => m,
                     };
                     return CaptureKind::Ref(mutability);
@@ -1229,7 +1231,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                     let mut mutability = Mutability::Not;
                     for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
                         match capture {
-                            CaptureKind::Value => break,
+                            CaptureKind::Value | CaptureKind::Use => break,
                             CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
                             CaptureKind::Ref(Mutability::Not) => (),
                         }
@@ -1239,7 +1241,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                 _ => break,
             },
             Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) {
-                CaptureKind::Value => break,
+                CaptureKind::Value | CaptureKind::Use => break,
                 capture @ CaptureKind::Ref(_) => return capture,
             },
             _ => break,
@@ -1294,6 +1296,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
                         if !self.locals.contains(&local_id) {
                             let capture = match capture.info.capture_kind {
                                 UpvarCapture::ByValue => CaptureKind::Value,
+                                UpvarCapture::ByUse => CaptureKind::Use,
                                 UpvarCapture::ByRef(kind) => match kind {
                                     BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not),
                                     BorrowKind::UniqueImmutable | BorrowKind::Mutable => {
@@ -3489,7 +3492,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
                 // a::b::c  ::d::sym refers to
                 // e::f::sym:: ::
                 // result should be super::super::super::super::e::f
-                if let DefPathData::TypeNs(s) = l {
+                if let DefPathData::TypeNs(Some(s)) = l {
                     path.push(s.to_string());
                 }
                 if let DefPathData::TypeNs(_) = r {
@@ -3500,7 +3503,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
             // a::b::sym:: ::    refers to
             // c::d::e  ::f::sym
             // when looking at `f`
-            Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()),
+            Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()),
             // consider:
             // a::b::c  ::d::sym refers to
             // e::f::sym:: ::
@@ -3514,7 +3517,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
         // `super` chain would be too long, just use the absolute path instead
         once(String::from("crate"))
             .chain(to.data.iter().filter_map(|el| {
-                if let DefPathData::TypeNs(sym) = el.data {
+                if let DefPathData::TypeNs(Some(sym)) = el.data {
                     Some(sym.to_string())
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 4a9ab17d4a6..24b4f0d9e6d 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -147,6 +147,7 @@ impl<'a> Sugg<'a> {
             | ExprKind::Become(..)
             | ExprKind::Struct(..)
             | ExprKind::Tup(..)
+            | ExprKind::Use(..)
             | ExprKind::Err(_)
             | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
             ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
@@ -217,6 +218,7 @@ impl<'a> Sugg<'a> {
             | ast::ExprKind::Try(..)
             | ast::ExprKind::TryBlock(..)
             | ast::ExprKind::Tup(..)
+            | ast::ExprKind::Use(..)
             | ast::ExprKind::Array(..)
             | ast::ExprKind::While(..)
             | ast::ExprKind::Await(..)
@@ -835,6 +837,8 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
 impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
         if let PlaceBase::Local(id) = cmt.place.base {
             let map = self.cx.tcx.hir();
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 3bf518f7fe7..a079fd940c0 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -66,6 +66,8 @@ impl MutVarsDelegate {
 impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
         if bk == ty::BorrowKind::Mutable {
             self.update(cmt);
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 2ac0efd7e39..63dd00f2de0 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -648,6 +648,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
                     helper(typeck, true, arg, f)?;
                 }
             },
+            ExprKind::Use(expr, _) => {
+                helper(typeck, true, expr, f)?;
+            },
             ExprKind::Index(borrowed, consumed, _)
             | ExprKind::Assign(borrowed, consumed, _)
             | ExprKind::AssignOp(_, borrowed, consumed) => {
diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs
index 4445ecb7ce8..7b12ba946b9 100644
--- a/src/tools/compiletest/src/raise_fd_limit.rs
+++ b/src/tools/compiletest/src/raise_fd_limit.rs
@@ -7,7 +7,6 @@
 #[cfg(target_vendor = "apple")]
 #[allow(non_camel_case_types)]
 pub unsafe fn raise_fd_limit() {
-    use std::mem::size_of_val;
     use std::ptr::null_mut;
     use std::{cmp, io};
 
diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs
index 885ed3b08fa..da1e74b4a56 100644
--- a/src/tools/compiletest/src/runtest/crashes.rs
+++ b/src/tools/compiletest/src/runtest/crashes.rs
@@ -15,7 +15,7 @@ impl TestCx<'_> {
         // if a test does not crash, consider it an error
         if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) {
             self.fatal(&format!(
-                "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \
+                "crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful \
                 name, add a doc-comment to the start of the test explaining why it exists and \
                 move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR \
                 description ensures that the corresponding ticket is auto-closed upon merge. \
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index 8900752bd4b..073116933bd 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -105,6 +105,11 @@ impl TestCx<'_> {
             .expect("stage0 rustc is required to run run-make tests");
         let mut rustc = Command::new(&stage0_rustc);
         rustc
+            // `rmake.rs` **must** be buildable by a stable compiler, it may not use *any* unstable
+            // library or compiler features. Here, we force the stage 0 rustc to consider itself as
+            // a stable-channel compiler via `RUSTC_BOOTSTRAP=-1` to prevent *any* unstable
+            // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc.
+            .env("RUSTC_BOOTSTRAP", "-1")
             .arg("-o")
             .arg(&recipe_bin)
             // Specify library search paths for `run_make_support`.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index f403fba2f9d..8b14b51496a 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-98a48781feb1220c0cf2feea23f9ef92cdfa7437
+90384941aae4ea38de00e4702b50757e9b882a19
diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
index e611d6e28f8..75167ab5b38 100644
--- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
+++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
@@ -1,5 +1,5 @@
 error: unsupported operation: `open` not available when isolation is enabled
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
+  --> RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC
    |
 LL |         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled
@@ -7,14 +7,14 @@ LL |         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a
    = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
    = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
    = note: BACKTRACE:
-   = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
-   = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::fs::PLATFORM::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   = note: inside `std::sys::fs::PLATFORM::File::open_c` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+   = note: inside `std::sys::fs::PLATFORM::File::open` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC
    = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC
    = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC
    = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 85ce38f57d6..c37cf15d40a 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -270,13 +270,13 @@ regexes! {
     // erase thread caller ids
     r"call [0-9]+"                  => "call ID",
     // erase platform module paths
-    "sys::pal::[a-z]+::"                  => "sys::pal::PLATFORM::",
+    r"\bsys::([a-z_]+)::[a-z]+::"   => "sys::$1::PLATFORM::",
     // Windows file paths
     r"\\"                           => "/",
     // erase Rust stdlib path
     "[^ \n`]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/",
     // erase platform file paths
-    "sys/pal/[a-z]+/"                    => "sys/pal/PLATFORM/",
+    r"\bsys/([a-z_]+)/[a-z]+\b"     => "sys/$1/PLATFORM",
     // erase paths into the crate registry
     r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)"  => "CARGO_REGISTRY/.../$1",
 }
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index 15ed03ad5c2..f9beffec750 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -14,5 +14,9 @@ build_helper = { path = "../../build_helper" }
 serde_json = "1.0"
 libc = "0.2"
 
+# FIXME(#137532): replace `os_pipe` with `anonymous_pipe` once it stabilizes and
+# reaches beta.
+os_pipe = "1.2.1"
+
 [lib]
 crate-type = ["lib", "dylib"]
diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs
index ca6ab3275c4..c0317633873 100644
--- a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs
+++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs
@@ -1,17 +1,15 @@
-use crate::{is_msvc, is_windows, uname};
+use crate::{is_msvc, is_win7, is_windows, uname};
 
 /// `EXTRACFLAGS`
 pub fn extra_c_flags() -> Vec<&'static str> {
     if is_windows() {
         if is_msvc() {
-            vec![
-                "ws2_32.lib",
-                "userenv.lib",
-                "advapi32.lib",
-                "bcrypt.lib",
-                "ntdll.lib",
-                "synchronization.lib",
-            ]
+            let mut libs =
+                vec!["ws2_32.lib", "userenv.lib", "bcrypt.lib", "ntdll.lib", "synchronization.lib"];
+            if is_win7() {
+                libs.push("advapi32.lib");
+            }
+            libs
         } else {
             vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
         }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index d40ec9c4116..e0ad3ee9bed 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -40,6 +40,8 @@ pub use bstr;
 pub use gimli;
 pub use libc;
 pub use object;
+// FIXME(#137532): replace with std `anonymous_pipe` once it stabilizes and reaches beta.
+pub use os_pipe;
 pub use regex;
 pub use serde_json;
 pub use similar;
@@ -82,7 +84,7 @@ pub use run::{cmd, run, run_fail, run_with_args};
 
 /// Helpers for checking target information.
 pub use targets::{
-    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, llvm_components_contain,
+    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_win7, llvm_components_contain,
     target, uname,
 };
 
diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs
index a16fca71d2e..86edbdf750b 100644
--- a/src/tools/run-make-support/src/targets.rs
+++ b/src/tools/run-make-support/src/targets.rs
@@ -28,6 +28,12 @@ pub fn is_windows_gnu() -> bool {
     target().ends_with("windows-gnu")
 }
 
+/// Check if target is win7.
+#[must_use]
+pub fn is_win7() -> bool {
+    target().contains("win7")
+}
+
 /// Check if target uses macOS.
 #[must_use]
 pub fn is_darwin() -> bool {
diff --git a/src/tools/rust-analyzer/.editorconfig b/src/tools/rust-analyzer/.editorconfig
index 6bb743a6736..2d28ebd4766 100644
--- a/src/tools/rust-analyzer/.editorconfig
+++ b/src/tools/rust-analyzer/.editorconfig
@@ -15,3 +15,6 @@ indent_size = 2
 
 [*.{yml,yaml}]
 indent_size = 2
+
+[COMMIT_EDITMSG]
+max_line_length = unset
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index bc770dbe71e..7a6b43a0531 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -35,19 +35,48 @@ jobs:
             typescript:
               - 'editors/code/**'
             proc_macros:
+              - 'crates/tt/**'
               - 'crates/proc-macro-api/**'
               - 'crates/proc-macro-srv/**'
               - 'crates/proc-macro-srv-cli/**'
 
-  rust:
+  proc-macro-srv:
     needs: changes
+    if: github.repository == 'rust-lang/rust-analyzer' && needs.changes.outputs.proc_macros == 'true'
+    name: proc-macro-srv
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ github.event.pull_request.head.sha }}
+
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update nightly
+          rustup default nightly
+          rustup component add --toolchain nightly rust-src rustfmt
+      # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
+      - name: Install Rust Problem Matcher
+        if: matrix.os == 'ubuntu-latest'
+        run: echo "::add-matcher::.github/rust.json"
+
+      - name: Cache Dependencies
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
+
+      - name: Bump opt-level
+        if: matrix.os == 'ubuntu-latest'
+        run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml
+
+      - name: Test
+        run: cargo test --features sysroot-abi -p rust-analyzer -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet
+
+  rust:
     if: github.repository == 'rust-lang/rust-analyzer'
     name: Rust
     runs-on: ${{ matrix.os }}
     env:
       CC: deny_c
-      RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable' }}"
-      USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || '' }}"
 
     strategy:
       fail-fast: false
@@ -62,13 +91,12 @@ jobs:
 
       - name: Install Rust toolchain
         run: |
-          rustup update --no-self-update ${{ env.RUST_CHANNEL }}
-          rustup default ${{ env.RUST_CHANNEL }}
-          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rust-src
+          rustup update --no-self-update stable
+          rustup default stable
+          rustup component add --toolchain stable rust-src
           # We always use a nightly rustfmt, regardless of channel, because we need
           # --file-lines.
-          rustup toolchain add nightly --profile minimal
-          rustup component add --toolchain nightly rustfmt
+          rustup toolchain install nightly --profile minimal --component rustfmt
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
         if: matrix.os == 'ubuntu-latest'
@@ -76,8 +104,6 @@ jobs:
 
       - name: Cache Dependencies
         uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
-        with:
-          key: ${{ env.RUST_CHANNEL }}
 
       - name: Bump opt-level
         if: matrix.os == 'ubuntu-latest'
@@ -87,16 +113,16 @@ jobs:
         run: cargo codegen --check
 
       - name: Compile (tests)
-        run: cargo test --no-run --locked ${{ env.USE_SYSROOT_ABI }}
+        run: cargo test --no-run --locked
 
       # It's faster to `test` before `build` ¯\_(ツ)_/¯
       - name: Compile (rust-analyzer)
         if: matrix.os == 'ubuntu-latest'
-        run: cargo build --quiet ${{ env.USE_SYSROOT_ABI }}
+        run: cargo build --quiet
 
       - name: Test
         if: matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest' || github.event_name == 'push'
-        run: cargo test ${{ env.USE_SYSROOT_ABI }} -- --nocapture --quiet
+        run: cargo test -- --quiet
 
       - name: Switch to stable toolchain
         run: |
@@ -157,7 +183,7 @@ jobs:
 
   typescript:
     needs: changes
-    if: github.repository == 'rust-lang/rust-analyzer'
+    if: github.repository == 'rust-lang/rust-analyzer' && needs.changes.outputs.typescript == 'true'
     name: TypeScript
     strategy:
       fail-fast: false
@@ -169,21 +195,18 @@ jobs:
     steps:
       - name: Checkout repository
         uses: actions/checkout@v4
-        if: needs.changes.outputs.typescript == 'true'
 
       - name: Install Nodejs
         uses: actions/setup-node@v4
         with:
           node-version: 22
-        if: needs.changes.outputs.typescript == 'true'
 
       - name: Install xvfb
-        if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true'
+        if: matrix.os == 'ubuntu-latest'
         run: sudo apt-get install -y xvfb
 
       - run: npm ci
         working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
 
       #    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
       #      if: runner.os == 'Linux'
@@ -192,27 +215,24 @@ jobs:
       # If this steps fails, your code's type integrity might be wrong at some places at TypeScript level.
       - run: npm run typecheck
         working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
 
       # You may fix the code automatically by running `npm run lint:fix` if this steps fails.
       - run: npm run lint
         working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
 
       # To fix this steps, please run `npm run format`.
       - run: npm run format:check
         working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
 
       - name: Run VS Code tests (Linux)
-        if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true'
+        if: matrix.os == 'ubuntu-latest'
         env:
           VSCODE_CLI: 1
         run: xvfb-run npm test
         working-directory: ./editors/code
 
       - name: Run VS Code tests (Windows)
-        if: matrix.os == 'windows-latest' && needs.changes.outputs.typescript == 'true'
+        if: matrix.os == 'windows-latest'
         env:
           VSCODE_CLI: 1
         run: npm test
@@ -220,7 +240,6 @@ jobs:
 
       - run: npm run package --scripts-prepend-node-path
         working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
 
   typo-check:
     name: Typo Check
@@ -242,7 +261,7 @@ jobs:
         run: typos
 
   conclusion:
-    needs: [rust, rust-cross, typescript, typo-check]
+    needs: [rust, rust-cross, typescript, typo-check, proc-macro-srv]
     # We need to ensure this job does *not* get skipped if its dependencies fail,
     # because a skipped job is considered a success by GitHub. So we have to
     # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
@@ -257,5 +276,5 @@ jobs:
         run: |
           # Print the dependent jobs to see them in the CI log
           jq -C <<< '${{ toJson(needs) }}'
-          # Check if all jobs that we depend on (in the needs array) were successful.
-          jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
+          # Check if all jobs that we depend on (in the needs array) were successful (or have been skipped).
+          jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index c57953ba654..1e1d68f7782 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -191,9 +191,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
 
 [[package]]
 name = "chalk-derive"
-version = "0.99.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "572583d9b97f9d277e5c7607f8239a30e2e04d3ed3b47c87d1cb2152ae724073"
+checksum = "ab2d131019373f0d0d1f2af0abd4f719739f6583c1b33965112455f643a910af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -203,9 +203,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.99.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e60e0ef9c81dce1336a9ed3c76f08775f5b623151d96d85ba45f7b10de76d1c7"
+checksum = "4f114996bda14c0213f014a4ef31a7867dcf5f539a3900477fc6b20138e7a17b"
 dependencies = [
  "bitflags 2.7.0",
  "chalk-derive",
@@ -213,9 +213,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.99.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a06350d614e22b03a69b8105e3541614450a7ea48bc58ecc6c6bd92731a3995"
+checksum = "551e956e031c09057c7b21f17d48d91de99c9b6b6e34bceaf5e7202d71021268"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -226,9 +226,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.99.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e428761e9b55bee516bfe2457caed8b6d1b86353f92ae825bbe438a36ce91e8"
+checksum = "cd7ca50181156ce649efe8e5dd00580f573651554e4dcd11afa4e2ac93f53324"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -626,7 +626,6 @@ dependencies = [
  "oorandom",
  "project-model",
  "ra-ap-rustc_abi",
- "ra-ap-rustc_hashes",
  "ra-ap-rustc_index",
  "ra-ap-rustc_pattern_analysis",
  "rustc-hash 2.0.0",
@@ -1504,9 +1503,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b42cccfff8091a4c3397736518774dbad619e82f8def6f70d8e46dbbe396007"
+checksum = "f1651b0f7e8c3eb7c27a88f39d277e69c32bfe58e3be174d286c1a24d6a7a4d8"
 dependencies = [
  "bitflags 2.7.0",
  "ra-ap-rustc_hashes",
@@ -1516,18 +1515,18 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_hashes"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46d8bd34ed6552c8cac1764106ef5adbeef3e5c7700e0ceb4c83a47a631894fe"
+checksum = "2bcd85e93dc0ea850bcfe7957a115957df799ccbc9eea488bdee5ec6780d212b"
 dependencies = [
  "rustc-stable-hash",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93799e4dccbbd47f8b66bc0aa42effc1b7077aaee09d8a40b86b8d659b80c7b7"
+checksum = "62b295fc0640cd9fe0ecab872ee4a17a96f90a3998ec9f0c4765e9b8415c12cc"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1535,9 +1534,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30baa5d00f94ba437a9dcaf7ae074ebe4f367bb05a4c2835e0aa2e7af3463aac"
+checksum = "c675f4257023aa933882906f13802cae287e88cc39ab13cbb96809083db0c801"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1546,9 +1545,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3004d1d1b50afe3e1f9cdd428a282da7ffbf5f26dd8bf04af0d651d44e4873d8"
+checksum = "c8358702c2a510ea84ba5801ddc047d9ad9520902cfb0e6173277610cdce2c9c"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1557,9 +1556,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb57e5124a64aaaf92c06130fbc1b8e1d547b5a2a96081f1f848e31c211df5d2"
+checksum = "b98f402011d46732c35c47bfd111dec0495747fef2ec900ddee7fe15d78449a7"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1567,9 +1566,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.98.0"
+version = "0.100.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e427c3d30e4bdff28abd6b0ef3e6f4dfab44acd9468a4954eeff8717d8df8819"
+checksum = "bef3ff73fa4653252ffe1d1e9177a446f49ef46d97140e4816b7ff2dad59ed53"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 1132acb6474..ce2d66000e3 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -85,12 +85,12 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 edition = { path = "./crates/edition", version = "0.0.0" }
 
-ra-ap-rustc_hashes = { version = "0.98", default-features = false }
-ra-ap-rustc_lexer = { version = "0.98", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.98", default-features = false }
-ra-ap-rustc_index = { version = "0.98", default-features = false }
-ra-ap-rustc_abi = { version = "0.98", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.98", default-features = false }
+ra-ap-rustc_hashes = { version = "0.100", default-features = false }
+ra-ap-rustc_lexer = { version = "0.100", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.100", default-features = false }
+ra-ap-rustc_index = { version = "0.100", default-features = false }
+ra-ap-rustc_abi = { version = "0.100", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.100", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
@@ -105,10 +105,10 @@ arrayvec = "0.7.4"
 bitflags = "2.4.1"
 cargo_metadata = "0.18.1"
 camino = "1.1.6"
-chalk-solve = { version = "0.99.0", default-features = false }
-chalk-ir = "0.99.0"
-chalk-recursive = { version = "0.99.0", default-features = false }
-chalk-derive = "0.99.0"
+chalk-solve = { version = "0.100.0", default-features = false }
+chalk-ir = "0.100.0"
+chalk-recursive = { version = "0.100.0", default-features = false }
+chalk-derive = "0.100.0"
 crossbeam-channel = "0.5.8"
 dissimilar = "1.0.7"
 dot = "0.1.4"
diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
index 84b91a527f0..0ec082dfa7f 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
@@ -18,6 +18,25 @@ pub enum CfgAtom {
     KeyValue { key: Symbol, value: Symbol },
 }
 
+impl PartialOrd for CfgAtom {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for CfgAtom {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        match (self, other) {
+            (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()),
+            (CfgAtom::Flag(_), CfgAtom::KeyValue { .. }) => std::cmp::Ordering::Less,
+            (CfgAtom::KeyValue { .. }, CfgAtom::Flag(_)) => std::cmp::Ordering::Greater,
+            (CfgAtom::KeyValue { key, value }, CfgAtom::KeyValue { key: key2, value: value2 }) => {
+                key.as_str().cmp(key2.as_str()).then(value.as_str().cmp(value2.as_str()))
+            }
+        }
+    }
+}
+
 impl fmt::Display for CfgAtom {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
diff --git a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
index f3ebca04650..424672a275e 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
@@ -66,9 +66,9 @@ impl DnfExpr {
             }
         }
 
-        res.enabled.sort_unstable_by(compare);
+        res.enabled.sort_unstable();
         res.enabled.dedup();
-        res.disabled.sort_unstable_by(compare);
+        res.disabled.sort_unstable();
         res.disabled.dedup();
         Some(res)
     }
@@ -114,25 +114,14 @@ impl DnfExpr {
             };
 
             // Undo the FxHashMap randomization for consistent output.
-            diff.enable.sort_unstable_by(compare);
-            diff.disable.sort_unstable_by(compare);
+            diff.enable.sort_unstable();
+            diff.disable.sort_unstable();
 
             Some(diff)
         })
     }
 }
 
-fn compare(a: &CfgAtom, b: &CfgAtom) -> std::cmp::Ordering {
-    match (a, b) {
-        (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()),
-        (CfgAtom::Flag(_), CfgAtom::KeyValue { .. }) => std::cmp::Ordering::Less,
-        (CfgAtom::KeyValue { .. }, CfgAtom::Flag(_)) => std::cmp::Ordering::Greater,
-        (CfgAtom::KeyValue { key, value }, CfgAtom::KeyValue { key: key2, value: value2 }) => {
-            key.as_str().cmp(key2.as_str()).then(value.as_str().cmp(value2.as_str()))
-        }
-    }
-}
-
 impl fmt::Display for DnfExpr {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if self.conjunctions.len() != 1 {
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index 6a6213a871f..08545b68511 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -148,16 +148,20 @@ pub struct CfgDiff {
 }
 
 impl CfgDiff {
-    /// Create a new CfgDiff. Will return None if the same item appears more than once in the set
-    /// of both.
-    pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> {
-        let mut occupied = FxHashSet::default();
-        if enable.iter().chain(disable.iter()).any(|item| !occupied.insert(item)) {
-            // was present
-            return None;
+    /// Create a new CfgDiff.
+    pub fn new(mut enable: Vec<CfgAtom>, mut disable: Vec<CfgAtom>) -> CfgDiff {
+        enable.sort();
+        enable.dedup();
+        disable.sort();
+        disable.dedup();
+        for i in (0..enable.len()).rev() {
+            if let Some(j) = disable.iter().position(|atom| *atom == enable[i]) {
+                enable.remove(i);
+                disable.remove(j);
+            }
         }
 
-        Some(CfgDiff { enable, disable })
+        CfgDiff { enable, disable }
     }
 
     /// Returns the total number of atoms changed by this diff.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index 6d4d519cd2b..6de4026dff7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -260,7 +260,7 @@ pub enum TypeBound {
 }
 
 #[cfg(target_pointer_width = "64")]
-const _: [(); 24] = [(); ::std::mem::size_of::<TypeBound>()];
+const _: [(); 24] = [(); size_of::<TypeBound>()];
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum UseArgRef {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
index c365a603d2a..138db1b498b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
@@ -93,15 +93,15 @@ fn broken_parenthesis_sequence() {
 macro_rules! m1 { ($x:ident) => { ($x } }
 macro_rules! m2 { ($x:ident) => {} }
 
-m1!();
-m2!(x
+fn f1() { m1!(x); }
+fn f2() { m2!(x }
 "#,
         expect![[r#"
 macro_rules! m1 { ($x:ident) => { ($x } }
 macro_rules! m2 { ($x:ident) => {} }
 
-/* error: macro definition has parse errors */
-/* error: expected ident */
+fn f1() { (x); }
+fn f2() { /* error: expected ident */ }
 "#]],
     )
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index e6c2504d07a..713e7389736 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -57,7 +57,7 @@ pub enum Path {
     /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
     /// this is not a problem since many more paths have generics than a type anchor).
     BarePath(Interned<ModPath>),
-    /// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
+    /// `Path::Normal` will always have either generics or type anchor.
     Normal(NormalPath),
     /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
     /// links via a normal path since they might be private and not accessible in the usage place.
@@ -208,11 +208,15 @@ impl Path {
                     mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
                 ));
                 let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
-                Some(Path::Normal(NormalPath::new(
-                    type_anchor,
-                    qualifier_mod_path,
-                    qualifier_generic_args.iter().cloned(),
-                )))
+                if type_anchor.is_none() && qualifier_generic_args.iter().all(|it| it.is_none()) {
+                    Some(Path::BarePath(qualifier_mod_path))
+                } else {
+                    Some(Path::Normal(NormalPath::new(
+                        type_anchor,
+                        qualifier_mod_path,
+                        qualifier_generic_args.iter().cloned(),
+                    )))
+                }
             }
             Path::LangItem(..) => None,
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index e5774b48044..a2e6e4cc043 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -3,10 +3,11 @@ use std::{fmt, iter, mem};
 
 use base_db::CrateId;
 use hir_expand::{name::Name, MacroDefId};
-use intern::sym;
+use intern::{sym, Symbol};
 use itertools::Itertools as _;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
+use span::SyntaxContextId;
 use triomphe::Arc;
 
 use crate::{
@@ -343,15 +344,7 @@ impl Resolver {
         }
 
         if n_segments <= 1 {
-            let mut hygiene_info = if !hygiene_id.is_root() {
-                let ctx = hygiene_id.lookup(db);
-                ctx.outer_expn.map(|expansion| {
-                    let expansion = db.lookup_intern_macro_call(expansion);
-                    (ctx.parent, expansion.def)
-                })
-            } else {
-                None
-            };
+            let mut hygiene_info = hygiene_info(db, hygiene_id);
             for scope in self.scopes() {
                 match scope {
                     Scope::ExprScope(scope) => {
@@ -371,19 +364,7 @@ impl Resolver {
                         }
                     }
                     Scope::MacroDefScope(macro_id) => {
-                        if let Some((parent_ctx, label_macro_id)) = hygiene_info {
-                            if label_macro_id == **macro_id {
-                                // A macro is allowed to refer to variables from before its declaration.
-                                // Therefore, if we got to the rib of its declaration, give up its hygiene
-                                // and use its parent expansion.
-                                let parent_ctx = db.lookup_intern_syntax_context(parent_ctx);
-                                hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
-                                hygiene_info = parent_ctx.outer_expn.map(|expansion| {
-                                    let expansion = db.lookup_intern_macro_call(expansion);
-                                    (parent_ctx.parent, expansion.def)
-                                });
-                            }
-                        }
+                        handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id)
                     }
                     Scope::GenericParams { params, def } => {
                         if let Some(id) = params.find_const_by_name(first_name, *def) {
@@ -730,6 +711,107 @@ impl Resolver {
         })
     }
 
+    /// Checks if we rename `renamed` (currently named `current_name`) to `new_name`, will the meaning of this reference
+    /// (that contains `current_name` path) change from `renamed` to some another variable (returned as `Some`).
+    pub fn rename_will_conflict_with_another_variable(
+        &self,
+        db: &dyn DefDatabase,
+        current_name: &Name,
+        current_name_as_path: &ModPath,
+        mut hygiene_id: HygieneId,
+        new_name: &Symbol,
+        to_be_renamed: BindingId,
+    ) -> Option<BindingId> {
+        let mut hygiene_info = hygiene_info(db, hygiene_id);
+        let mut will_be_resolved_to = None;
+        for scope in self.scopes() {
+            match scope {
+                Scope::ExprScope(scope) => {
+                    for entry in scope.expr_scopes.entries(scope.scope_id) {
+                        if entry.hygiene() == hygiene_id {
+                            if entry.binding() == to_be_renamed {
+                                // This currently resolves to our renamed variable, now `will_be_resolved_to`
+                                // contains `Some` if the meaning will change or `None` if not.
+                                return will_be_resolved_to;
+                            } else if entry.name().symbol() == new_name {
+                                will_be_resolved_to = Some(entry.binding());
+                            }
+                        }
+                    }
+                }
+                Scope::MacroDefScope(macro_id) => {
+                    handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id)
+                }
+                Scope::GenericParams { params, def } => {
+                    if params.find_const_by_name(current_name, *def).is_some() {
+                        // It does not resolve to our renamed variable.
+                        return None;
+                    }
+                }
+                Scope::AdtScope(_) | Scope::ImplDefScope(_) => continue,
+                Scope::BlockScope(m) => {
+                    if m.resolve_path_in_value_ns(db, current_name_as_path).is_some() {
+                        // It does not resolve to our renamed variable.
+                        return None;
+                    }
+                }
+            }
+        }
+        // It does not resolve to our renamed variable.
+        None
+    }
+
+    /// Checks if we rename `renamed` to `name`, will the meaning of this reference (that contains `name` path) change
+    /// from some other variable (returned as `Some`) to `renamed`.
+    pub fn rename_will_conflict_with_renamed(
+        &self,
+        db: &dyn DefDatabase,
+        name: &Name,
+        name_as_path: &ModPath,
+        mut hygiene_id: HygieneId,
+        to_be_renamed: BindingId,
+    ) -> Option<BindingId> {
+        let mut hygiene_info = hygiene_info(db, hygiene_id);
+        let mut will_resolve_to_renamed = false;
+        for scope in self.scopes() {
+            match scope {
+                Scope::ExprScope(scope) => {
+                    for entry in scope.expr_scopes.entries(scope.scope_id) {
+                        if entry.binding() == to_be_renamed {
+                            will_resolve_to_renamed = true;
+                        } else if entry.hygiene() == hygiene_id && entry.name() == name {
+                            if will_resolve_to_renamed {
+                                // This will resolve to the renamed variable before it resolves to the original variable.
+                                return Some(entry.binding());
+                            } else {
+                                // This will resolve to the original variable.
+                                return None;
+                            }
+                        }
+                    }
+                }
+                Scope::MacroDefScope(macro_id) => {
+                    handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id)
+                }
+                Scope::GenericParams { params, def } => {
+                    if params.find_const_by_name(name, *def).is_some() {
+                        // Here and below, it might actually resolve to our renamed variable - in which case it'll
+                        // hide the generic parameter or some other thing (not a variable). We don't check for that
+                        // because due to naming conventions, it is rare that variable will shadow a non-variable.
+                        return None;
+                    }
+                }
+                Scope::AdtScope(_) | Scope::ImplDefScope(_) => continue,
+                Scope::BlockScope(m) => {
+                    if m.resolve_path_in_value_ns(db, name_as_path).is_some() {
+                        return None;
+                    }
+                }
+            }
+        }
+        None
+    }
+
     /// `expr_id` is required to be an expression id that comes after the top level expression scope in the given resolver
     #[must_use]
     pub fn update_to_inner_scope(
@@ -795,6 +877,44 @@ impl Resolver {
     }
 }
 
+#[inline]
+fn handle_macro_def_scope(
+    db: &dyn DefDatabase,
+    hygiene_id: &mut HygieneId,
+    hygiene_info: &mut Option<(SyntaxContextId, MacroDefId)>,
+    macro_id: &MacroDefId,
+) {
+    if let Some((parent_ctx, label_macro_id)) = hygiene_info {
+        if label_macro_id == macro_id {
+            // A macro is allowed to refer to variables from before its declaration.
+            // Therefore, if we got to the rib of its declaration, give up its hygiene
+            // and use its parent expansion.
+            let parent_ctx = db.lookup_intern_syntax_context(*parent_ctx);
+            *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
+            *hygiene_info = parent_ctx.outer_expn.map(|expansion| {
+                let expansion = db.lookup_intern_macro_call(expansion);
+                (parent_ctx.parent, expansion.def)
+            });
+        }
+    }
+}
+
+#[inline]
+fn hygiene_info(
+    db: &dyn DefDatabase,
+    hygiene_id: HygieneId,
+) -> Option<(SyntaxContextId, MacroDefId)> {
+    if !hygiene_id.is_root() {
+        let ctx = hygiene_id.lookup(db);
+        ctx.outer_expn.map(|expansion| {
+            let expansion = db.lookup_intern_macro_call(expansion);
+            (ctx.parent, expansion.def)
+        })
+    } else {
+        None
+    }
+}
+
 pub struct UpdateGuard(usize);
 
 impl Resolver {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index eb430177390..28894537d48 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -148,7 +148,6 @@ pub(crate) fn fixup_syntax(
                     }
                     if it.then_branch().is_none() {
                         append.insert(node.clone().into(), vec![
-                            // FIXME: THis should be a subtree no?
                             Leaf::Punct(Punct {
                                 char: '{',
                                 spacing: Spacing::Alone,
@@ -179,7 +178,6 @@ pub(crate) fn fixup_syntax(
                     }
                     if it.loop_body().is_none() {
                         append.insert(node.clone().into(), vec![
-                            // FIXME: THis should be a subtree no?
                             Leaf::Punct(Punct {
                                 char: '{',
                                 spacing: Spacing::Alone,
@@ -196,7 +194,6 @@ pub(crate) fn fixup_syntax(
                 ast::LoopExpr(it) => {
                     if it.loop_body().is_none() {
                         append.insert(node.clone().into(), vec![
-                            // FIXME: THis should be a subtree no?
                             Leaf::Punct(Punct {
                                 char: '{',
                                 spacing: Spacing::Alone,
@@ -228,7 +225,6 @@ pub(crate) fn fixup_syntax(
                     if it.match_arm_list().is_none() {
                         // No match arms
                         append.insert(node.clone().into(), vec![
-                            // FIXME: THis should be a subtree no?
                             Leaf::Punct(Punct {
                                 char: '{',
                                 spacing: Spacing::Alone,
@@ -269,7 +265,6 @@ pub(crate) fn fixup_syntax(
 
                     if it.loop_body().is_none() {
                         append.insert(node.clone().into(), vec![
-                            // FIXME: THis should be a subtree no?
                             Leaf::Punct(Punct {
                                 char: '{',
                                 spacing: Spacing::Alone,
@@ -309,28 +304,6 @@ pub(crate) fn fixup_syntax(
                         }
                     }
                 },
-                ast::ArgList(it) => {
-                    if it.r_paren_token().is_none() {
-                        append.insert(node.into(), vec![
-                            Leaf::Punct(Punct {
-                                span: fake_span(node_range),
-                                char: ')',
-                                spacing: Spacing::Alone
-                            })
-                        ]);
-                    }
-                },
-                ast::ArgList(it) => {
-                    if it.r_paren_token().is_none() {
-                        append.insert(node.into(), vec![
-                            Leaf::Punct(Punct {
-                                span: fake_span(node_range),
-                                char: ')',
-                                spacing: Spacing::Alone
-                            })
-                        ]);
-                    }
-                },
                 ast::ClosureExpr(it) => {
                     if it.body().is_none() {
                         append.insert(node.into(), vec![
@@ -476,12 +449,12 @@ fn reverse_fixups_(tt: &mut TopSubtree, undo_info: &[TopSubtree]) {
             }
         }
         tt::TokenTree::Subtree(tt) => {
+            // fixup should only create matching delimiters, but proc macros
+            // could just copy the span to one of the delimiters. We don't want
+            // to leak the dummy ID, so we remove both.
             if tt.delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID
                 || tt.delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID
             {
-                // Even though fixup never creates subtrees with fixup spans, the old proc-macro server
-                // might copy them if the proc-macro asks for it, so we need to filter those out
-                // here as well.
                 return TransformTtAction::remove();
             }
             TransformTtAction::Keep
@@ -571,6 +544,17 @@ mod tests {
             parse.syntax_node()
         );
 
+        // the fixed-up tree should not contain braces as punct
+        // FIXME: should probably instead check that it's a valid punctuation character
+        for x in tt.token_trees().flat_tokens() {
+            match x {
+                ::tt::TokenTree::Leaf(::tt::Leaf::Punct(punct)) => {
+                    assert!(!matches!(punct.char, '{' | '}' | '(' | ')' | '[' | ']'))
+                }
+                _ => (),
+            }
+        }
+
         reverse_fixups(&mut tt, &fixups.undo_info);
 
         // the fixed-up + reversed version should be equivalent to the original input
@@ -596,7 +580,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {for _ in __ra_fixup { }}
+fn foo () {for _ in __ra_fixup {}}
 "#]],
         )
     }
@@ -624,7 +608,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {for bar in qux { }}
+fn foo () {for bar in qux {}}
 "#]],
         )
     }
@@ -655,7 +639,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {match __ra_fixup { }}
+fn foo () {match __ra_fixup {}}
 "#]],
         )
     }
@@ -687,7 +671,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {match __ra_fixup { }}
+fn foo () {match __ra_fixup {}}
 "#]],
         )
     }
@@ -802,7 +786,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {if a { }}
+fn foo () {if a {}}
 "#]],
         )
     }
@@ -816,7 +800,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {if __ra_fixup { }}
+fn foo () {if __ra_fixup {}}
 "#]],
         )
     }
@@ -830,7 +814,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {if __ra_fixup {} { }}
+fn foo () {if __ra_fixup {} {}}
 "#]],
         )
     }
@@ -844,7 +828,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {while __ra_fixup { }}
+fn foo () {while __ra_fixup {}}
 "#]],
         )
     }
@@ -858,7 +842,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {while foo { }}
+fn foo () {while foo {}}
 "#]],
         )
     }
@@ -885,7 +869,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {loop { }}
+fn foo () {loop {}}
 "#]],
         )
     }
@@ -941,7 +925,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () { foo ( a ) }
+fn foo () {foo (a)}
 "#]],
         );
         check(
@@ -951,7 +935,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () { bar . foo ( a ) }
+fn foo () {bar . foo (a)}
 "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 41603e3c92e..c1d808cbf2c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -5,6 +5,8 @@
 //! expansion.
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 
+pub use intern;
+
 pub mod attrs;
 pub mod builtin;
 pub mod change;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index f0cf7ebf479..75b58614540 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -388,7 +388,7 @@ macro_rules! __path {
     ($start:ident $(:: $seg:ident)*) => ({
         $crate::__known_path!($start $(:: $seg)*);
         $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Abs, vec![
-            $crate::name::Name::new_symbol_root(intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root(intern::sym::$seg.clone()),)*
+            $crate::name::Name::new_symbol_root($crate::intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root($crate::intern::sym::$seg.clone()),)*
         ])
     });
 }
@@ -399,7 +399,7 @@ pub use crate::__path as path;
 macro_rules! __tool_path {
     ($start:ident $(:: $seg:ident)*) => ({
         $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Plain, vec![
-            $crate::name::Name::new_symbol_root(intern::sym::rust_analyzer.clone()), $crate::name::Name::new_symbol_root(intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root(intern::sym::$seg.clone()),)*
+            $crate::name::Name::new_symbol_root($crate::intern::sym::rust_analyzer.clone()), $crate::name::Name::new_symbol_root($crate::intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root($crate::intern::sym::$seg.clone()),)*
         ])
     });
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 27849f3b449..1d12bee646c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -35,7 +35,6 @@ indexmap.workspace = true
 rustc_apfloat = "0.2.0"
 
 ra-ap-rustc_abi.workspace = true
-ra-ap-rustc_hashes.workspace = true
 ra-ap-rustc_index.workspace = true
 ra-ap-rustc_pattern_analysis.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index c8ff6cba3dd..67fb73696f7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -708,6 +708,9 @@ fn well_known_trait_from_lang_item(item: LangItem) -> Option<WellKnownTrait> {
         LangItem::Fn => WellKnownTrait::Fn,
         LangItem::FnMut => WellKnownTrait::FnMut,
         LangItem::FnOnce => WellKnownTrait::FnOnce,
+        LangItem::AsyncFn => WellKnownTrait::AsyncFn,
+        LangItem::AsyncFnMut => WellKnownTrait::AsyncFnMut,
+        LangItem::AsyncFnOnce => WellKnownTrait::AsyncFnOnce,
         LangItem::Coroutine => WellKnownTrait::Coroutine,
         LangItem::Sized => WellKnownTrait::Sized,
         LangItem::Unpin => WellKnownTrait::Unpin,
@@ -715,6 +718,7 @@ fn well_known_trait_from_lang_item(item: LangItem) -> Option<WellKnownTrait> {
         LangItem::Tuple => WellKnownTrait::Tuple,
         LangItem::PointeeTrait => WellKnownTrait::Pointee,
         LangItem::FnPtrTrait => WellKnownTrait::FnPtr,
+        LangItem::Future => WellKnownTrait::Future,
         _ => return None,
     })
 }
@@ -730,6 +734,9 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem {
         WellKnownTrait::Fn => LangItem::Fn,
         WellKnownTrait::FnMut => LangItem::FnMut,
         WellKnownTrait::FnOnce => LangItem::FnOnce,
+        WellKnownTrait::AsyncFn => LangItem::AsyncFn,
+        WellKnownTrait::AsyncFnMut => LangItem::AsyncFnMut,
+        WellKnownTrait::AsyncFnOnce => LangItem::AsyncFnOnce,
         WellKnownTrait::Coroutine => LangItem::Coroutine,
         WellKnownTrait::Sized => LangItem::Sized,
         WellKnownTrait::Tuple => LangItem::Tuple,
@@ -737,6 +744,7 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem {
         WellKnownTrait::Unsize => LangItem::Unsize,
         WellKnownTrait::Pointee => LangItem::PointeeTrait,
         WellKnownTrait::FnPtr => LangItem::FnPtrTrait,
+        WellKnownTrait::Future => LangItem::Future,
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 7839589994b..fb604569f43 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -15,9 +15,10 @@ use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode,
-    mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue,
-    GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder,
+    db::HirDatabase, display::DisplayTarget, generics::Generics, infer::InferenceContext,
+    lower::ParamLoweringMode, mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData,
+    ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
+    TyBuilder,
 };
 
 use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -62,11 +63,15 @@ impl ConstEvalError {
         f: &mut String,
         db: &dyn HirDatabase,
         span_formatter: impl Fn(span::FileId, span::TextRange) -> String,
-        edition: span::Edition,
+        display_target: DisplayTarget,
     ) -> std::result::Result<(), std::fmt::Error> {
         match self {
-            ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter, edition),
-            ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter, edition),
+            ConstEvalError::MirLowerError(e) => {
+                e.pretty_print(f, db, span_formatter, display_target)
+            }
+            ConstEvalError::MirEvalError(e) => {
+                e.pretty_print(f, db, span_formatter, display_target)
+            }
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 2d7d4cacd2c..26a3b702297 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -10,8 +10,8 @@ use test_fixture::WithFixture;
 use test_utils::skip_slow_tests;
 
 use crate::{
-    consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar,
-    Interner, MemoryMap,
+    consteval::try_const_usize, db::HirDatabase, display::DisplayTarget, mir::pad16,
+    test_db::TestDB, Const, ConstScalar, Interner, MemoryMap,
 };
 
 use super::{
@@ -101,11 +101,17 @@ fn check_answer(
 fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
     let mut err = String::new();
     let span_formatter = |file, range| format!("{file:?} {range:?}");
-    let edition =
-        db.crate_graph()[*db.crate_graph().crates_in_topological_order().last().unwrap()].edition;
+    let display_target = DisplayTarget::from_crate(
+        &db,
+        *db.crate_graph().crates_in_topological_order().last().unwrap(),
+    );
     match e {
-        ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
-        ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
+        ConstEvalError::MirLowerError(e) => {
+            e.pretty_print(&mut err, &db, span_formatter, display_target)
+        }
+        ConstEvalError::MirEvalError(e) => {
+            e.pretty_print(&mut err, &db, span_formatter, display_target)
+        }
     }
     .unwrap();
     err
@@ -2713,12 +2719,11 @@ fn const_trait_assoc() {
         r#"
     //- minicore: size_of, fn
     //- /a/lib.rs crate:a
-    use core::mem::size_of;
     pub struct S<T>(T);
     impl<T> S<T> {
         pub const X: usize = {
             let k: T;
-            let f = || core::mem::size_of::<T>();
+            let f = || size_of::<T>();
             f()
         };
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
index 30c02a2936d..845d3333353 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
@@ -9,5 +9,8 @@ pub use crate::diagnostics::{
     expr::{
         record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
     },
-    unsafe_check::{missing_unsafe, unsafe_expressions, InsideUnsafeBlock, UnsafetyReason},
+    unsafe_check::{
+        missing_unsafe, unsafe_operations, unsafe_operations_for_body, InsideUnsafeBlock,
+        UnsafetyReason,
+    },
 };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 59aaf85164a..cc6f4d9e52e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -16,7 +16,6 @@ use intern::sym;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::constructor::Constructor;
-use span::Edition;
 use syntax::{
     ast::{self, UnaryOp},
     AstNode,
@@ -31,7 +30,7 @@ use crate::{
         self,
         pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat},
     },
-    display::HirDisplay,
+    display::{DisplayTarget, HirDisplay},
     Adjust, InferenceResult, Interner, Ty, TyExt, TyKind,
 };
 
@@ -633,24 +632,24 @@ fn missing_match_arms<'p>(
     arms_is_empty: bool,
     krate: CrateId,
 ) -> String {
-    struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, Edition);
+    struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget);
     impl fmt::Display for DisplayWitness<'_, '_> {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            let DisplayWitness(witness, cx, edition) = *self;
+            let DisplayWitness(witness, cx, display_target) = *self;
             let pat = cx.hoist_witness_pat(witness);
-            write!(f, "{}", pat.display(cx.db, edition))
+            write!(f, "{}", pat.display(cx.db, display_target))
         }
     }
 
-    let edition = cx.db.crate_graph()[krate].edition;
     let non_empty_enum = match scrut_ty.as_adt() {
         Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
         _ => false,
     };
+    let display_target = DisplayTarget::from_crate(cx.db, krate);
     if arms_is_empty && !non_empty_enum {
-        format!("type `{}` is non-empty", scrut_ty.display(cx.db, edition))
+        format!("type `{}` is non-empty", scrut_ty.display(cx.db, display_target))
     } else {
-        let pat_display = |witness| DisplayWitness(witness, cx, edition);
+        let pat_display = |witness| DisplayWitness(witness, cx, display_target);
         const LIMIT: usize = 3;
         match &*witnesses {
             [witness] => format!("`{}` not covered", pat_display(witness)),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index ac849b0762d..d2b908839c4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -95,7 +95,26 @@ enum UnsafeDiagnostic {
     DeprecatedSafe2024 { node: ExprId, inside_unsafe_block: InsideUnsafeBlock },
 }
 
-pub fn unsafe_expressions(
+pub fn unsafe_operations_for_body(
+    db: &dyn HirDatabase,
+    infer: &InferenceResult,
+    def: DefWithBodyId,
+    body: &Body,
+    callback: &mut dyn FnMut(ExprOrPatId),
+) {
+    let mut visitor_callback = |diag| {
+        if let UnsafeDiagnostic::UnsafeOperation { node, .. } = diag {
+            callback(node);
+        }
+    };
+    let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut visitor_callback);
+    visitor.walk_expr(body.body_expr);
+    for &param in &body.params {
+        visitor.walk_pat(param);
+    }
+}
+
+pub fn unsafe_operations(
     db: &dyn HirDatabase,
     infer: &InferenceResult,
     def: DefWithBodyId,
@@ -281,13 +300,6 @@ impl<'a> UnsafeVisitor<'a> {
                     self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref);
                 }
             }
-            Expr::Unsafe { .. } => {
-                let old_inside_unsafe_block =
-                    mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
-                self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
-                self.inside_unsafe_block = old_inside_unsafe_block;
-                return;
-            }
             &Expr::Assignment { target, value: _ } => {
                 let old_inside_assignment = mem::replace(&mut self.inside_assignment, true);
                 self.walk_pats_top(std::iter::once(target), current);
@@ -306,6 +318,20 @@ impl<'a> UnsafeVisitor<'a> {
                     }
                 }
             }
+            Expr::Unsafe { statements, .. } => {
+                let old_inside_unsafe_block =
+                    mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
+                self.walk_pats_top(
+                    statements.iter().filter_map(|statement| match statement {
+                        &Statement::Let { pat, .. } => Some(pat),
+                        _ => None,
+                    }),
+                    current,
+                );
+                self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
+                self.inside_unsafe_block = old_inside_unsafe_block;
+                return;
+            }
             Expr::Block { statements, .. } | Expr::Async { statements, .. } => {
                 self.walk_pats_top(
                     statements.iter().filter_map(|statement| match statement {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 49f061813d1..95ce36390d3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -4,7 +4,7 @@
 
 use std::{
     fmt::{self, Debug},
-    mem::{self, size_of},
+    mem,
 };
 
 use base_db::CrateId;
@@ -45,6 +45,7 @@ use crate::{
     db::{HirDatabase, InternedClosure},
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
     generics::generics,
+    infer::normalize,
     layout::Layout,
     lt_from_placeholder_idx,
     mapping::from_chalk,
@@ -87,6 +88,7 @@ pub struct HirFormatter<'a> {
     show_container_bounds: bool,
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
+    display_kind: DisplayKind,
     display_target: DisplayTarget,
     bounds_formatting_ctx: BoundsFormattingCtx,
 }
@@ -164,6 +166,7 @@ pub trait HirDisplay {
         limited_size: Option<usize>,
         omit_verbose_types: bool,
         display_target: DisplayTarget,
+        display_kind: DisplayKind,
         closure_style: ClosureStyle,
         show_container_bounds: bool,
     ) -> HirDisplayWrapper<'a, Self>
@@ -171,7 +174,7 @@ pub trait HirDisplay {
         Self: Sized,
     {
         assert!(
-            !matches!(display_target, DisplayTarget::SourceCode { .. }),
+            !matches!(display_kind, DisplayKind::SourceCode { .. }),
             "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
         );
         HirDisplayWrapper {
@@ -181,6 +184,7 @@ pub trait HirDisplay {
             limited_size,
             omit_verbose_types,
             display_target,
+            display_kind,
             closure_style,
             show_container_bounds,
         }
@@ -191,7 +195,7 @@ pub trait HirDisplay {
     fn display<'a>(
         &'a self,
         db: &'a dyn HirDatabase,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -203,7 +207,8 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics { edition },
+            display_target,
+            display_kind: DisplayKind::Diagnostics,
             show_container_bounds: false,
         }
     }
@@ -214,7 +219,7 @@ pub trait HirDisplay {
         &'a self,
         db: &'a dyn HirDatabase,
         max_size: Option<usize>,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -226,7 +231,8 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics { edition },
+            display_target,
+            display_kind: DisplayKind::Diagnostics,
             show_container_bounds: false,
         }
     }
@@ -237,7 +243,7 @@ pub trait HirDisplay {
         &'a self,
         db: &'a dyn HirDatabase,
         limited_size: Option<usize>,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -249,7 +255,8 @@ pub trait HirDisplay {
             limited_size,
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics { edition },
+            display_target,
+            display_kind: DisplayKind::Diagnostics,
             show_container_bounds: false,
         }
     }
@@ -272,7 +279,8 @@ pub trait HirDisplay {
             entity_limit: None,
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
+            display_target: DisplayTarget::from_crate(db, module_id.krate()),
+            display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque },
             show_container_bounds: false,
             bounds_formatting_ctx: Default::default(),
         }) {
@@ -284,7 +292,11 @@ pub trait HirDisplay {
     }
 
     /// Returns a String representation of `self` for test purposes
-    fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
+    fn display_test<'a>(
+        &'a self,
+        db: &'a dyn HirDatabase,
+        display_target: DisplayTarget,
+    ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
     {
@@ -295,7 +307,8 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Test,
+            display_target,
+            display_kind: DisplayKind::Test,
             show_container_bounds: false,
         }
     }
@@ -306,7 +319,7 @@ pub trait HirDisplay {
         &'a self,
         db: &'a dyn HirDatabase,
         show_container_bounds: bool,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -318,21 +331,20 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics { edition },
+            display_target,
+            display_kind: DisplayKind::Diagnostics,
             show_container_bounds,
         }
     }
 }
 
 impl HirFormatter<'_> {
+    pub fn krate(&self) -> CrateId {
+        self.display_target.krate
+    }
+
     pub fn edition(&self) -> Edition {
-        match self.display_target {
-            DisplayTarget::Diagnostics { edition } => edition,
-            DisplayTarget::SourceCode { module_id, .. } => {
-                self.db.crate_graph()[module_id.krate()].edition
-            }
-            DisplayTarget::Test => Edition::CURRENT,
-        }
+        self.display_target.edition
     }
 
     pub fn write_joined<T: HirDisplay>(
@@ -394,20 +406,33 @@ impl HirFormatter<'_> {
     }
 }
 
+#[derive(Debug, Clone, Copy)]
+pub struct DisplayTarget {
+    krate: CrateId,
+    pub edition: Edition,
+}
+
+impl DisplayTarget {
+    pub fn from_crate(db: &dyn HirDatabase, krate: CrateId) -> Self {
+        let edition = db.crate_graph()[krate].edition;
+        Self { krate, edition }
+    }
+}
+
 #[derive(Clone, Copy)]
-pub enum DisplayTarget {
+pub enum DisplayKind {
     /// Display types for inlays, doc popups, autocompletion, etc...
     /// Showing `{unknown}` or not qualifying paths is fine here.
     /// There's no reason for this to fail.
-    Diagnostics { edition: Edition },
+    Diagnostics,
     /// Display types for inserting them in source files.
     /// The generated code should compile, so paths need to be qualified.
-    SourceCode { module_id: ModuleId, allow_opaque: bool },
+    SourceCode { target_module_id: ModuleId, allow_opaque: bool },
     /// Only for test purpose to keep real types
     Test,
 }
 
-impl DisplayTarget {
+impl DisplayKind {
     fn is_source_code(self) -> bool {
         matches!(self, Self::SourceCode { .. })
     }
@@ -450,6 +475,7 @@ pub struct HirDisplayWrapper<'a, T> {
     limited_size: Option<usize>,
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
+    display_kind: DisplayKind,
     display_target: DisplayTarget,
     show_container_bounds: bool,
 }
@@ -479,6 +505,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
             max_size: self.max_size,
             entity_limit: self.limited_size,
             omit_verbose_types: self.omit_verbose_types,
+            display_kind: self.display_kind,
             display_target: self.display_target,
             closure_style: self.closure_style,
             show_container_bounds: self.show_container_bounds,
@@ -533,7 +560,7 @@ impl HirDisplay for ProjectionTy {
         // if we are projection on a type parameter, check if the projection target has bounds
         // itself, if so, we render them directly as `impl Bound` instead of the less useful
         // `<Param as Trait>::Assoc`
-        if !f.display_target.is_source_code() {
+        if !f.display_kind.is_source_code() {
             if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
                 if !f.bounds_formatting_ctx.contains(self) {
                     let db = f.db;
@@ -653,10 +680,8 @@ fn render_const_scalar(
     memory_map: &MemoryMap,
     ty: &Ty,
 ) -> Result<(), HirDisplayError> {
-    // FIXME: We need to get krate from the final callers of the hir display
-    // infrastructure and have it here as a field on `f`.
-    let trait_env =
-        TraitEnvironment::empty(*f.db.crate_graph().crates_in_topological_order().last().unwrap());
+    let trait_env = TraitEnvironment::empty(f.krate());
+    let ty = normalize(f.db, trait_env.clone(), ty.clone());
     match ty.kind(Interner) {
         TyKind::Scalar(s) => match s {
             Scalar::Bool => write!(f, "{}", b[0] != 0),
@@ -1109,7 +1134,7 @@ impl HirDisplay for Ty {
                 let def = from_chalk(db, *def);
                 let sig = db.callable_item_signature(def).substitute(Interner, parameters);
 
-                if f.display_target.is_source_code() {
+                if f.display_kind.is_source_code() {
                     // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
                     // function pointer type.
                     return sig.hir_fmt(f);
@@ -1198,8 +1223,8 @@ impl HirDisplay for Ty {
             }
             TyKind::Adt(AdtId(def_id), parameters) => {
                 f.start_location_link((*def_id).into());
-                match f.display_target {
-                    DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => {
+                match f.display_kind {
+                    DisplayKind::Diagnostics { .. } | DisplayKind::Test { .. } => {
                         let name = match *def_id {
                             hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
                             hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
@@ -1207,7 +1232,7 @@ impl HirDisplay for Ty {
                         };
                         write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
                     }
-                    DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
+                    DisplayKind::SourceCode { target_module_id: module_id, allow_opaque: _ } => {
                         if let Some(path) = find_path::find_path(
                             db.upcast(),
                             ItemInNs::Types((*def_id).into()),
@@ -1246,7 +1271,7 @@ impl HirDisplay for Ty {
                 let type_alias_data = db.type_alias_data(type_alias);
 
                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
-                if f.display_target.is_test() {
+                if f.display_kind.is_test() {
                     f.start_location_link(trait_.into());
                     write!(f, "{}", trait_data.name.display(f.db.upcast(), f.edition()))?;
                     f.end_location_link();
@@ -1275,7 +1300,7 @@ impl HirDisplay for Ty {
                 f.end_location_link();
             }
             TyKind::OpaqueType(opaque_ty_id, parameters) => {
-                if !f.display_target.allows_opaque() {
+                if !f.display_kind.allows_opaque() {
                     return Err(HirDisplayError::DisplaySourceCodeError(
                         DisplaySourceCodeError::OpaqueType,
                     ));
@@ -1344,8 +1369,8 @@ impl HirDisplay for Ty {
                 }
             }
             TyKind::Closure(id, substs) => {
-                if f.display_target.is_source_code() {
-                    if !f.display_target.allows_opaque() {
+                if f.display_kind.is_source_code() {
+                    if !f.display_kind.allows_opaque() {
                         return Err(HirDisplayError::DisplaySourceCodeError(
                             DisplaySourceCodeError::OpaqueType,
                         ));
@@ -1465,7 +1490,7 @@ impl HirDisplay for Ty {
             }
             TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
-                if !f.display_target.allows_opaque() {
+                if !f.display_kind.allows_opaque() {
                     return Err(HirDisplayError::DisplaySourceCodeError(
                         DisplaySourceCodeError::OpaqueType,
                     ));
@@ -1508,7 +1533,7 @@ impl HirDisplay for Ty {
                 };
             }
             TyKind::Error => {
-                if f.display_target.is_source_code() {
+                if f.display_kind.is_source_code() {
                     f.write_char('_')?;
                 } else {
                     write!(f, "{{unknown}}")?;
@@ -1516,7 +1541,7 @@ impl HirDisplay for Ty {
             }
             TyKind::InferenceVar(..) => write!(f, "_")?,
             TyKind::Coroutine(_, subst) => {
-                if f.display_target.is_source_code() {
+                if f.display_kind.is_source_code() {
                     return Err(HirDisplayError::DisplaySourceCodeError(
                         DisplaySourceCodeError::Coroutine,
                     ));
@@ -1573,7 +1598,7 @@ fn generic_args_sans_defaults<'ga>(
     generic_def: Option<hir_def::GenericDefId>,
     parameters: &'ga [GenericArg],
 ) -> &'ga [GenericArg] {
-    if f.display_target.is_source_code() || f.omit_verbose_types() {
+    if f.display_kind.is_source_code() || f.omit_verbose_types() {
         match generic_def
             .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
             .filter(|it| !it.is_empty())
@@ -1958,7 +1983,7 @@ impl HirDisplay for LifetimeData {
                 write!(f, "{}", param_data.name.display(f.db.upcast(), f.edition()))?;
                 Ok(())
             }
-            _ if f.display_target.is_source_code() => write!(f, "'_"),
+            _ if f.display_kind.is_source_code() => write!(f, "'_"),
             LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
             LifetimeData::InferenceVar(_) => write!(f, "_"),
             LifetimeData::Static => write!(f, "'static"),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 7af31dabe45..bbd419d9659 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -6,16 +6,14 @@ use base_db::ra_salsa::Cycle;
 use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
 use hir_def::{
     layout::{
-        BackendRepr, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError,
-        LayoutData, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout,
-        WrappingRange,
+        Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive,
+        ReprOptions, Scalar, StructKind, TargetDataLayout, WrappingRange,
     },
     LocalFieldId, StructId,
 };
 use la_arena::{Idx, RawIdx};
 use rustc_abi::AddressSpace;
-use rustc_hashes::Hash64;
-use rustc_index::{IndexSlice, IndexVec};
+use rustc_index::IndexVec;
 
 use triomphe::Arc;
 
@@ -23,7 +21,6 @@ use crate::{
     consteval::try_const_usize,
     db::{HirDatabase, InternedClosure},
     infer::normalize,
-    layout::adt::struct_variant_idx,
     utils::ClosureSubst,
     Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
 };
@@ -125,10 +122,10 @@ impl<'a> LayoutCx<'a> {
     }
 }
 
-// FIXME: move this to the `rustc_abi`.
 fn layout_of_simd_ty(
     db: &dyn HirDatabase,
     id: StructId,
+    repr_packed: bool,
     subst: &Substitution,
     env: Arc<TraitEnvironment>,
     dl: &TargetDataLayout,
@@ -149,33 +146,10 @@ fn layout_of_simd_ty(
     };
 
     let e_len = try_const_usize(db, &e_len).ok_or(LayoutError::HasErrorConst)? as u64;
-
-    // Compute the ABI of the element type:
     let e_ly = db.layout_of_ty(e_ty, env)?;
-    let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else {
-        return Err(LayoutError::Unknown);
-    };
 
-    // Compute the size and alignment of the vector:
-    let size = e_ly
-        .size
-        .checked_mul(e_len, dl)
-        .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?;
-    let align = dl.llvmlike_vector_align(size);
-    let size = size.align_to(align.abi);
-
-    Ok(Arc::new(Layout {
-        variants: Variants::Single { index: struct_variant_idx() },
-        fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() },
-        backend_repr: BackendRepr::SimdVector { element: e_abi, count: e_len },
-        largest_niche: e_ly.largest_niche,
-        uninhabited: false,
-        size,
-        align,
-        max_repr_align: None,
-        unadjusted_abi_align: align.abi,
-        randomization_seed: Hash64::ZERO,
-    }))
+    let cx = LayoutCx::new(dl);
+    Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?))
 }
 
 pub fn layout_of_ty_query(
@@ -190,13 +164,14 @@ pub fn layout_of_ty_query(
     let dl = &*target;
     let cx = LayoutCx::new(dl);
     let ty = normalize(db, trait_env.clone(), ty);
-    let result = match ty.kind(Interner) {
+    let kind = ty.kind(Interner);
+    let result = match kind {
         TyKind::Adt(AdtId(def), subst) => {
             if let hir_def::AdtId::StructId(s) = def {
                 let data = db.struct_data(*s);
                 let repr = data.repr.unwrap_or_default();
                 if repr.simd() {
-                    return layout_of_simd_ty(db, *s, subst, trait_env, &target);
+                    return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target);
                 }
             };
             return db.layout_of_adt(*def, subst.clone(), trait_env);
@@ -216,42 +191,51 @@ pub fn layout_of_ty_query(
                     valid_range: WrappingRange { start: 0, end: 0x10FFFF },
                 },
             ),
-            chalk_ir::Scalar::Int(i) => scalar(
+            chalk_ir::Scalar::Int(i) => Layout::scalar(
                 dl,
-                Primitive::Int(
-                    match i {
-                        IntTy::Isize => dl.ptr_sized_integer(),
-                        IntTy::I8 => Integer::I8,
-                        IntTy::I16 => Integer::I16,
-                        IntTy::I32 => Integer::I32,
-                        IntTy::I64 => Integer::I64,
-                        IntTy::I128 => Integer::I128,
-                    },
-                    true,
+                scalar_unit(
+                    dl,
+                    Primitive::Int(
+                        match i {
+                            IntTy::Isize => dl.ptr_sized_integer(),
+                            IntTy::I8 => Integer::I8,
+                            IntTy::I16 => Integer::I16,
+                            IntTy::I32 => Integer::I32,
+                            IntTy::I64 => Integer::I64,
+                            IntTy::I128 => Integer::I128,
+                        },
+                        true,
+                    ),
                 ),
             ),
-            chalk_ir::Scalar::Uint(i) => scalar(
+            chalk_ir::Scalar::Uint(i) => Layout::scalar(
                 dl,
-                Primitive::Int(
-                    match i {
-                        UintTy::Usize => dl.ptr_sized_integer(),
-                        UintTy::U8 => Integer::I8,
-                        UintTy::U16 => Integer::I16,
-                        UintTy::U32 => Integer::I32,
-                        UintTy::U64 => Integer::I64,
-                        UintTy::U128 => Integer::I128,
-                    },
-                    false,
+                scalar_unit(
+                    dl,
+                    Primitive::Int(
+                        match i {
+                            UintTy::Usize => dl.ptr_sized_integer(),
+                            UintTy::U8 => Integer::I8,
+                            UintTy::U16 => Integer::I16,
+                            UintTy::U32 => Integer::I32,
+                            UintTy::U64 => Integer::I64,
+                            UintTy::U128 => Integer::I128,
+                        },
+                        false,
+                    ),
                 ),
             ),
-            chalk_ir::Scalar::Float(f) => scalar(
+            chalk_ir::Scalar::Float(f) => Layout::scalar(
                 dl,
-                Primitive::Float(match f {
-                    FloatTy::F16 => Float::F16,
-                    FloatTy::F32 => Float::F32,
-                    FloatTy::F64 => Float::F64,
-                    FloatTy::F128 => Float::F128,
-                }),
+                scalar_unit(
+                    dl,
+                    Primitive::Float(match f {
+                        FloatTy::F16 => Float::F16,
+                        FloatTy::F32 => Float::F32,
+                        FloatTy::F64 => Float::F64,
+                        FloatTy::F128 => Float::F128,
+                    }),
+                ),
             ),
         },
         TyKind::Tuple(len, tys) => {
@@ -268,56 +252,16 @@ pub fn layout_of_ty_query(
         TyKind::Array(element, count) => {
             let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
             let element = db.layout_of_ty(element.clone(), trait_env)?;
-            let size = element
-                .size
-                .checked_mul(count, dl)
-                .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?;
-
-            let backend_repr = BackendRepr::Memory { sized: true };
-
-            let largest_niche = if count != 0 { element.largest_niche } else { None };
-            let uninhabited = if count != 0 { element.uninhabited } else { false };
-
-            Layout {
-                variants: Variants::Single { index: struct_variant_idx() },
-                fields: FieldsShape::Array { stride: element.size, count },
-                backend_repr,
-                largest_niche,
-                uninhabited,
-                align: element.align,
-                size,
-                max_repr_align: None,
-                unadjusted_abi_align: element.align.abi,
-                randomization_seed: Hash64::ZERO,
-            }
+            cx.calc.array_like::<_, _, ()>(&element, Some(count))?
         }
         TyKind::Slice(element) => {
             let element = db.layout_of_ty(element.clone(), trait_env)?;
-            Layout {
-                variants: Variants::Single { index: struct_variant_idx() },
-                fields: FieldsShape::Array { stride: element.size, count: 0 },
-                backend_repr: BackendRepr::Memory { sized: false },
-                largest_niche: None,
-                uninhabited: false,
-                align: element.align,
-                size: Size::ZERO,
-                max_repr_align: None,
-                unadjusted_abi_align: element.align.abi,
-                randomization_seed: Hash64::ZERO,
-            }
+            cx.calc.array_like::<_, _, ()>(&element, None)?
+        }
+        TyKind::Str => {
+            let element = scalar_unit(dl, Primitive::Int(Integer::I8, false));
+            cx.calc.array_like::<_, _, ()>(&Layout::scalar(dl, element), None)?
         }
-        TyKind::Str => Layout {
-            variants: Variants::Single { index: struct_variant_idx() },
-            fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
-            backend_repr: BackendRepr::Memory { sized: false },
-            largest_niche: None,
-            uninhabited: false,
-            align: dl.i8_align,
-            size: Size::ZERO,
-            max_repr_align: None,
-            unadjusted_abi_align: dl.i8_align.abi,
-            randomization_seed: Hash64::ZERO,
-        },
         // Potentially-wide pointers.
         TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
             let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
@@ -355,17 +299,12 @@ pub fn layout_of_ty_query(
             };
 
             // Effectively a (ptr, meta) tuple.
-            cx.calc.scalar_pair(data_ptr, metadata)
+            LayoutData::scalar_pair(dl, data_ptr, metadata)
         }
-        TyKind::FnDef(_, _) => layout_of_unit(&cx)?,
-        TyKind::Never => cx.calc.layout_of_never_type(),
-        TyKind::Dyn(_) | TyKind::Foreign(_) => {
-            let mut unit = layout_of_unit(&cx)?;
-            match &mut unit.backend_repr {
-                BackendRepr::Memory { sized } => *sized = false,
-                _ => return Err(LayoutError::Unknown),
-            }
-            unit
+        TyKind::Never => LayoutData::never_type(dl),
+        TyKind::FnDef(..) | TyKind::Dyn(_) | TyKind::Foreign(_) => {
+            let sized = matches!(kind, TyKind::FnDef(..));
+            LayoutData::unit(dl, sized)
         }
         TyKind::Function(_) => {
             let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space));
@@ -410,6 +349,9 @@ pub fn layout_of_ty_query(
         TyKind::Error => return Err(LayoutError::HasErrorType),
         TyKind::AssociatedType(id, subst) => {
             // Try again with `TyKind::Alias` to normalize the associated type.
+            // Usually we should not try to normalize `TyKind::AssociatedType`, but layout calculation is used
+            // in monomorphized MIR where this is okay. If outside monomorphization, this will lead to cycle,
+            // which we will recover from with an error.
             let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
                 associated_ty_id: *id,
                 substitution: subst.clone(),
@@ -434,16 +376,6 @@ pub fn layout_of_ty_recover(
     Err(LayoutError::RecursiveTypeWithoutIndirection)
 }
 
-fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> {
-    cx.calc
-        .univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
-            IndexSlice::empty(),
-            &ReprOptions::default(),
-            StructKind::AlwaysSized,
-        )
-        .map_err(Into::into)
-}
-
 fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
     match pointee.kind(Interner) {
         TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => {
@@ -474,9 +406,5 @@ fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
     Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
 }
 
-fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
-    Layout::scalar(dl, scalar_unit(dl, value))
-}
-
 #[cfg(test)]
 mod tests;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 0ba765bd75e..eb4729fab84 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -16,16 +16,12 @@ use triomphe::Arc;
 use crate::{
     db::HirDatabase,
     lang_items::is_unsafe_cell,
-    layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
+    layout::{field_ty, Layout, LayoutError},
     Substitution, TraitEnvironment,
 };
 
 use super::LayoutCx;
 
-pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx {
-    RustcEnumVariantIdx(0)
-}
-
 pub fn layout_of_adt_query(
     db: &dyn HirDatabase,
     def: AdtId,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 4d3896660b4..8b74b7328bd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -342,7 +342,7 @@ fn simd_types() {
     check_size_and_align(
         r#"
             #[repr(simd)]
-            struct SimdType(i64, i64);
+            struct SimdType([i64; 2]);
             struct Goal(SimdType);
         "#,
         "",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 707c4377726..624767cedf8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -12,9 +12,6 @@ extern crate ra_ap_rustc_index as rustc_index;
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_abi;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_hashes;
-
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_abi as rustc_abi;
 
@@ -24,9 +21,6 @@ extern crate rustc_pattern_analysis;
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
 
-#[cfg(not(feature = "in-rust-tree"))]
-extern crate ra_ap_rustc_hashes as rustc_hashes;
-
 mod builder;
 mod chalk_db;
 mod chalk_ext;
@@ -76,13 +70,15 @@ use intern::{sym, Symbol};
 use la_arena::{Arena, Idx};
 use mir::{MirEvalError, VTableMap};
 use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
-use span::Edition;
 use syntax::ast::{make, ConstArg};
 use traits::FnTrait;
 use triomphe::Arc;
 
 use crate::{
-    consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics,
+    consteval::unknown_const,
+    db::HirDatabase,
+    display::{DisplayTarget, HirDisplay},
+    generics::Generics,
     infer::unify::InferenceTable,
 };
 
@@ -1044,7 +1040,7 @@ where
 pub fn known_const_to_ast(
     konst: &Const,
     db: &dyn HirDatabase,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<ConstArg> {
     if let ConstValue::Concrete(c) = &konst.interned().value {
         match c.interned {
@@ -1055,7 +1051,7 @@ pub fn known_const_to_ast(
             _ => (),
         }
     }
-    Some(make::expr_const_value(konst.display(db, edition).to_string().as_str()))
+    Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str()))
 }
 
 #[derive(Debug, Copy, Clone)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 41304bbd8a9..56c431ef8da 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -5,7 +5,7 @@ use std::{collections::hash_map::Entry, fmt::Display, iter};
 use crate::{
     consteval::usize_const,
     db::HirDatabase,
-    display::HirDisplay,
+    display::{DisplayTarget, HirDisplay},
     infer::{normalize, PointerCast},
     lang_items::is_box,
     mapping::ToChalk,
@@ -168,7 +168,7 @@ impl<V, T> ProjectionElem<V, T> {
                 _ => {
                     never!(
                         "Overloaded deref on type {} is not a projection",
-                        base.display(db, db.crate_graph()[krate].edition)
+                        base.display(db, DisplayTarget::from_crate(db, krate))
                     );
                     TyKind::Error.intern(Interner)
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 9c86d3b59f6..fbcca388e78 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -13,6 +13,7 @@ use triomphe::Arc;
 
 use crate::{
     db::{HirDatabase, InternedClosure},
+    display::DisplayTarget,
     mir::Operand,
     utils::ClosureSubst,
     ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags,
@@ -422,7 +423,10 @@ fn ever_initialized_map(
             let Some(terminator) = &block.terminator else {
                 never!(
                     "Terminator should be none only in construction.\nThe body:\n{}",
-                    body.pretty_print(db)
+                    body.pretty_print(
+                        db,
+                        DisplayTarget::from_crate(db, body.owner.krate(db.upcast()))
+                    )
                 );
                 return;
             };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 6b20522cf34..74a34e29817 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -24,7 +24,7 @@ use rustc_apfloat::{
     Float,
 };
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Edition, FileId};
+use span::FileId;
 use stdx::never;
 use syntax::{SyntaxNodePtr, TextRange};
 use triomphe::Arc;
@@ -32,7 +32,7 @@ use triomphe::Arc;
 use crate::{
     consteval::{intern_const_scalar, try_const_usize, ConstEvalError},
     db::{HirDatabase, InternedClosure},
-    display::{ClosureStyle, HirDisplay},
+    display::{ClosureStyle, DisplayTarget, HirDisplay},
     infer::PointerCast,
     layout::{Layout, LayoutError, RustcEnumVariantIdx},
     mapping::from_chalk,
@@ -302,7 +302,7 @@ impl Address {
         }
     }
 
-    fn to_bytes(&self) -> [u8; mem::size_of::<usize>()] {
+    fn to_bytes(&self) -> [u8; size_of::<usize>()] {
         usize::to_le_bytes(self.to_usize())
     }
 
@@ -359,7 +359,7 @@ impl MirEvalError {
         f: &mut String,
         db: &dyn HirDatabase,
         span_formatter: impl Fn(FileId, TextRange) -> String,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> std::result::Result<(), std::fmt::Error> {
         writeln!(f, "Mir eval error:")?;
         let mut err = self;
@@ -372,7 +372,7 @@ impl MirEvalError {
                         writeln!(
                             f,
                             "In function {} ({:?})",
-                            function_name.name.display(db.upcast(), edition),
+                            function_name.name.display(db.upcast(), display_target.edition),
                             func
                         )?;
                     }
@@ -417,7 +417,7 @@ impl MirEvalError {
                 write!(
                     f,
                     "Layout for type `{}` is not available due {err:?}",
-                    ty.display(db, edition).with_closure_style(ClosureStyle::ClosureWithId)
+                    ty.display(db, display_target).with_closure_style(ClosureStyle::ClosureWithId)
                 )?;
             }
             MirEvalError::MirLowerError(func, err) => {
@@ -428,12 +428,15 @@ impl MirEvalError {
                         let substs = generics.placeholder_subst(db);
                         db.impl_self_ty(impl_id)
                             .substitute(Interner, &substs)
-                            .display(db, edition)
+                            .display(db, display_target)
                             .to_string()
                     }),
-                    ItemContainerId::TraitId(it) => {
-                        Some(db.trait_data(it).name.display(db.upcast(), edition).to_string())
-                    }
+                    ItemContainerId::TraitId(it) => Some(
+                        db.trait_data(it)
+                            .name
+                            .display(db.upcast(), display_target.edition)
+                            .to_string(),
+                    ),
                     _ => None,
                 };
                 writeln!(
@@ -441,17 +444,17 @@ impl MirEvalError {
                     "MIR lowering for function `{}{}{}` ({:?}) failed due:",
                     self_.as_deref().unwrap_or_default(),
                     if self_.is_some() { "::" } else { "" },
-                    function_name.name.display(db.upcast(), edition),
+                    function_name.name.display(db.upcast(), display_target.edition),
                     func
                 )?;
-                err.pretty_print(f, db, span_formatter, edition)?;
+                err.pretty_print(f, db, span_formatter, display_target)?;
             }
             MirEvalError::ConstEvalError(name, err) => {
                 MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
                     f,
                     db,
                     span_formatter,
-                    edition,
+                    display_target,
                 )?;
             }
             MirEvalError::UndefinedBehavior(_)
@@ -589,7 +592,7 @@ pub fn interpret_mir(
     let ty = body.locals[return_slot()].ty.clone();
     let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;
     let it: Result<Const> = (|| {
-        if evaluator.ptr_size() != std::mem::size_of::<usize>() {
+        if evaluator.ptr_size() != size_of::<usize>() {
             not_supported!("targets with different pointer size from host");
         }
         let interval = evaluator.interpret_mir(body.clone(), None.into_iter())?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 7d3376f56be..f61ecabb7e4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -14,6 +14,7 @@ use intern::{sym, Symbol};
 use stdx::never;
 
 use crate::{
+    display::DisplayTarget,
     error_lifetime,
     mir::eval::{
         pad16, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay,
@@ -835,8 +836,7 @@ impl Evaluator<'_> {
                     // render full paths.
                     Err(_) => {
                         let krate = locals.body.owner.krate(self.db.upcast());
-                        let edition = self.db.crate_graph()[krate].edition;
-                        ty.display(self.db, edition).to_string()
+                        ty.display(self.db, DisplayTarget::from_crate(self.db, krate)).to_string()
                     }
                 };
                 let len = ty_name.len();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 2b5486fc5fa..084c391d26c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -3,6 +3,7 @@ use span::{Edition, EditionedFileId};
 use syntax::{TextRange, TextSize};
 use test_fixture::WithFixture;
 
+use crate::display::DisplayTarget;
 use crate::{db::HirDatabase, mir::MirLowerError, test_db::TestDB, Interner, Substitution};
 
 use super::{interpret_mir, MirEvalError};
@@ -67,7 +68,9 @@ fn check_pass_and_stdio(
             let span_formatter = |file, range: TextRange| {
                 format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end()))
             };
-            e.pretty_print(&mut err, &db, span_formatter, Edition::CURRENT).unwrap();
+            let krate = db.module_for_file(file_id).krate();
+            e.pretty_print(&mut err, &db, span_formatter, DisplayTarget::from_crate(&db, krate))
+                .unwrap();
             panic!("Error in interpreting: {err}");
         }
         Ok((stdout, stderr)) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index f88696692e6..520717e7995 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -2,7 +2,7 @@
 
 use std::{fmt::Write, iter, mem};
 
-use base_db::ra_salsa::Cycle;
+use base_db::{ra_salsa::Cycle, CrateId};
 use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
 use hir_def::{
     data::adt::{StructKind, VariantData},
@@ -29,7 +29,7 @@ use triomphe::Arc;
 use crate::{
     consteval::ConstEvalError,
     db::{HirDatabase, InternedClosure},
-    display::{hir_display_with_types_map, HirDisplay},
+    display::{hir_display_with_types_map, DisplayTarget, HirDisplay},
     error_lifetime,
     generics::generics,
     infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@@ -160,17 +160,17 @@ impl MirLowerError {
         f: &mut String,
         db: &dyn HirDatabase,
         span_formatter: impl Fn(FileId, TextRange) -> String,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> std::result::Result<(), std::fmt::Error> {
         match self {
             MirLowerError::ConstEvalError(name, e) => {
                 writeln!(f, "In evaluating constant {name}")?;
                 match &**e {
                     ConstEvalError::MirLowerError(e) => {
-                        e.pretty_print(f, db, span_formatter, edition)?
+                        e.pretty_print(f, db, span_formatter, display_target)?
                     }
                     ConstEvalError::MirEvalError(e) => {
-                        e.pretty_print(f, db, span_formatter, edition)?
+                        e.pretty_print(f, db, span_formatter, display_target)?
                     }
                 }
             }
@@ -179,15 +179,15 @@ impl MirLowerError {
                 writeln!(
                     f,
                     "Missing function definition for {}",
-                    body.pretty_print_expr(db.upcast(), *owner, *it, edition)
+                    body.pretty_print_expr(db.upcast(), *owner, *it, display_target.edition)
                 )?;
             }
             MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
             MirLowerError::TypeMismatch(e) => writeln!(
                 f,
                 "Type mismatch: Expected {}, found {}",
-                e.expected.display(db, edition),
-                e.actual.display(db, edition),
+                e.expected.display(db, display_target),
+                e.actual.display(db, display_target),
             )?,
             MirLowerError::GenericArgNotProvided(id, subst) => {
                 let parent = id.parent;
@@ -195,11 +195,14 @@ impl MirLowerError {
                 writeln!(
                     f,
                     "Generic arg not provided for {}",
-                    param.name().unwrap_or(&Name::missing()).display(db.upcast(), edition)
+                    param
+                        .name()
+                        .unwrap_or(&Name::missing())
+                        .display(db.upcast(), display_target.edition)
                 )?;
                 writeln!(f, "Provided args: [")?;
                 for g in subst.iter(Interner) {
-                    write!(f, "    {},", g.display(db, edition))?;
+                    write!(f, "    {},", g.display(db, display_target))?;
                 }
                 writeln!(f, "]")?;
             }
@@ -251,11 +254,11 @@ impl MirLowerError {
     fn unresolved_path(
         db: &dyn HirDatabase,
         p: &Path,
-        edition: Edition,
+        display_target: DisplayTarget,
         types_map: &TypesMap,
     ) -> Self {
         Self::UnresolvedName(
-            hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
+            hir_display_with_types_map(p, types_map).display(db, display_target).to_string(),
         )
     }
 }
@@ -462,7 +465,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                             MirLowerError::unresolved_path(
                                 self.db,
                                 p,
-                                self.edition(),
+                                DisplayTarget::from_crate(self.db, self.krate()),
                                 &self.body.types,
                             )
                         })?;
@@ -838,7 +841,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
                         Some(p) => MirLowerError::UnresolvedName(
                             hir_display_with_types_map(&**p, &self.body.types)
-                                .display(self.db, self.edition())
+                                .display(self.db, self.display_target())
                                 .to_string(),
                         ),
                         None => MirLowerError::RecordLiteralWithoutPath,
@@ -1362,9 +1365,16 @@ impl<'ctx> MirLowerCtx<'ctx> {
         match &self.body.exprs[*loc] {
             Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
             Expr::Path(c) => {
-                let edition = self.edition();
-                let unresolved_name =
-                    || MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
+                let owner = self.owner;
+                let db = self.db;
+                let unresolved_name = || {
+                    MirLowerError::unresolved_path(
+                        self.db,
+                        c,
+                        DisplayTarget::from_crate(db, owner.krate(db.upcast())),
+                        &self.body.types,
+                    )
+                };
                 let pr = self
                     .resolver
                     .resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT)
@@ -1394,7 +1404,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))
                 .map(|it| it.size.bytes_usize())
         };
-        const USIZE_SIZE: usize = mem::size_of::<usize>();
+        const USIZE_SIZE: usize = size_of::<usize>();
         let bytes: Box<[_]> = match l {
             hir_def::hir::Literal::String(b) => {
                 let b = b.as_str();
@@ -1910,8 +1920,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
     }
 
     fn edition(&self) -> Edition {
-        let krate = self.owner.krate(self.db.upcast());
-        self.db.crate_graph()[krate].edition
+        self.db.crate_graph()[self.krate()].edition
+    }
+
+    fn krate(&self) -> CrateId {
+        self.owner.krate(self.db.upcast())
+    }
+
+    fn display_target(&self) -> DisplayTarget {
+        DisplayTarget::from_crate(self.db, self.krate())
     }
 
     fn drop_until_scope(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 289175feefb..783f92b2043 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -350,7 +350,12 @@ impl MirLowerCtx<'_> {
                 )?,
                 None => {
                     let unresolved_name = || {
-                        MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
+                        MirLowerError::unresolved_path(
+                            self.db,
+                            p,
+                            self.display_target(),
+                            &self.body.types,
+                        )
                     };
                     let hygiene = self.body.pat_path_hygiene(pattern);
                     let pr = self
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 2a26101ac43..7d7d4106cb9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -9,11 +9,10 @@ use either::Either;
 use hir_def::{expr_store::Body, hir::BindingId};
 use hir_expand::{name::Name, Lookup};
 use la_arena::ArenaMap;
-use span::Edition;
 
 use crate::{
     db::HirDatabase,
-    display::{ClosureStyle, HirDisplay},
+    display::{ClosureStyle, DisplayTarget, HirDisplay},
     mir::{PlaceElem, ProjectionElem, StatementKind, TerminatorKind},
     ClosureId,
 };
@@ -39,17 +38,21 @@ macro_rules! wln {
 }
 
 impl MirBody {
-    pub fn pretty_print(&self, db: &dyn HirDatabase) -> String {
+    pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
         let hir_body = db.body(self.owner);
-        let mut ctx = MirPrettyCtx::new(self, &hir_body, db);
+        let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target);
         ctx.for_body(|this| match ctx.body.owner {
             hir_def::DefWithBodyId::FunctionId(id) => {
                 let data = db.function_data(id);
-                w!(this, "fn {}() ", data.name.display(db.upcast(), Edition::LATEST));
+                w!(this, "fn {}() ", data.name.display(db.upcast(), this.display_target.edition));
             }
             hir_def::DefWithBodyId::StaticId(id) => {
                 let data = db.static_data(id);
-                w!(this, "static {}: _ = ", data.name.display(db.upcast(), Edition::LATEST));
+                w!(
+                    this,
+                    "static {}: _ = ",
+                    data.name.display(db.upcast(), this.display_target.edition)
+                );
             }
             hir_def::DefWithBodyId::ConstId(id) => {
                 let data = db.const_data(id);
@@ -59,7 +62,7 @@ impl MirBody {
                     data.name
                         .as_ref()
                         .unwrap_or(&Name::missing())
-                        .display(db.upcast(), Edition::LATEST)
+                        .display(db.upcast(), this.display_target.edition)
                 );
             }
             hir_def::DefWithBodyId::VariantId(id) => {
@@ -70,10 +73,10 @@ impl MirBody {
                     "enum {}::{} = ",
                     enum_loc.id.item_tree(db.upcast())[enum_loc.id.value]
                         .name
-                        .display(db.upcast(), Edition::LATEST),
+                        .display(db.upcast(), this.display_target.edition),
                     loc.id.item_tree(db.upcast())[loc.id.value]
                         .name
-                        .display(db.upcast(), Edition::LATEST),
+                        .display(db.upcast(), this.display_target.edition),
                 )
             }
             hir_def::DefWithBodyId::InTypeConstId(id) => {
@@ -85,14 +88,14 @@ impl MirBody {
 
     // String with lines is rendered poorly in `dbg` macros, which I use very much, so this
     // function exists to solve that.
-    pub fn dbg(&self, db: &dyn HirDatabase) -> impl Debug {
+    pub fn dbg(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> impl Debug {
         struct StringDbg(String);
         impl Debug for StringDbg {
             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 f.write_str(&self.0)
             }
         }
-        StringDbg(self.pretty_print(db))
+        StringDbg(self.pretty_print(db, display_target))
     }
 }
 
@@ -103,6 +106,7 @@ struct MirPrettyCtx<'a> {
     result: String,
     indent: String,
     local_to_binding: ArenaMap<LocalId, BindingId>,
+    display_target: DisplayTarget,
 }
 
 impl Write for MirPrettyCtx<'_> {
@@ -182,7 +186,12 @@ impl<'a> MirPrettyCtx<'a> {
         wln!(self, "}}");
     }
 
-    fn new(body: &'a MirBody, hir_body: &'a Body, db: &'a dyn HirDatabase) -> Self {
+    fn new(
+        body: &'a MirBody,
+        hir_body: &'a Body,
+        db: &'a dyn HirDatabase,
+        display_target: DisplayTarget,
+    ) -> Self {
         let local_to_binding = body.local_to_binding_map();
         MirPrettyCtx {
             body,
@@ -191,6 +200,7 @@ impl<'a> MirPrettyCtx<'a> {
             indent: String::new(),
             local_to_binding,
             hir_body,
+            display_target,
         }
     }
 
@@ -208,7 +218,7 @@ impl<'a> MirPrettyCtx<'a> {
             wln!(
                 self,
                 "let {}: {};",
-                self.local_name(id).display_test(self.db),
+                self.local_name(id).display_test(self.db, self.display_target),
                 self.hir_display(&local.ty)
             );
         }
@@ -242,14 +252,14 @@ impl<'a> MirPrettyCtx<'a> {
                             wln!(
                                 this,
                                 "StorageDead({})",
-                                this.local_name(*p).display_test(self.db)
+                                this.local_name(*p).display_test(this.db, this.display_target)
                             );
                         }
                         StatementKind::StorageLive(p) => {
                             wln!(
                                 this,
                                 "StorageLive({})",
-                                this.local_name(*p).display_test(self.db)
+                                this.local_name(*p).display_test(this.db, this.display_target)
                             );
                         }
                         StatementKind::Deinit(p) => {
@@ -313,7 +323,7 @@ impl<'a> MirPrettyCtx<'a> {
         fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) {
             let Some((last, head)) = projections.split_last() else {
                 // no projection
-                w!(this, "{}", this.local_name(local).display_test(this.db));
+                w!(this, "{}", this.local_name(local).display_test(this.db, this.display_target));
                 return;
             };
             match last {
@@ -333,13 +343,17 @@ impl<'a> MirPrettyCtx<'a> {
                             w!(
                                 this,
                                 " as {}).{}",
-                                variant_name.display(this.db.upcast(), Edition::LATEST),
-                                name.display(this.db.upcast(), Edition::LATEST)
+                                variant_name.display(this.db.upcast(), this.display_target.edition),
+                                name.display(this.db.upcast(), this.display_target.edition)
                             );
                         }
                         hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => {
                             f(this, local, head);
-                            w!(this, ".{}", name.display(this.db.upcast(), Edition::LATEST));
+                            w!(
+                                this,
+                                ".{}",
+                                name.display(this.db.upcast(), this.display_target.edition)
+                            );
                         }
                     }
                 }
@@ -353,7 +367,11 @@ impl<'a> MirPrettyCtx<'a> {
                 }
                 ProjectionElem::Index(l) => {
                     f(this, local, head);
-                    w!(this, "[{}]", this.local_name(*l).display_test(this.db));
+                    w!(
+                        this,
+                        "[{}]",
+                        this.local_name(*l).display_test(this.db, this.display_target)
+                    );
                 }
                 it => {
                     f(this, local, head);
@@ -403,7 +421,7 @@ impl<'a> MirPrettyCtx<'a> {
             Rvalue::Repeat(op, len) => {
                 w!(self, "[");
                 self.operand(op);
-                w!(self, "; {}]", len.display_test(self.db));
+                w!(self, "; {}]", len.display_test(self.db, self.display_target));
             }
             Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => {
                 w!(self, "Adt(");
@@ -478,6 +496,7 @@ impl<'a> MirPrettyCtx<'a> {
     }
 
     fn hir_display<T: HirDisplay>(&self, ty: &'a T) -> impl Display + 'a {
-        ty.display_test(self.db).with_closure_style(ClosureStyle::ClosureWithSubst)
+        ty.display_test(self.db, self.display_target)
+            .with_closure_style(ClosureStyle::ClosureWithSubst)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index f5a4d4ff35c..81e38be2285 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -15,7 +15,7 @@ mod type_alias_impl_traits;
 use std::env;
 use std::sync::LazyLock;
 
-use base_db::SourceDatabaseFileInputExt as _;
+use base_db::{CrateId, SourceDatabaseFileInputExt as _};
 use expect_test::Expect;
 use hir_def::{
     db::DefDatabase,
@@ -41,7 +41,7 @@ use triomphe::Arc;
 
 use crate::{
     db::HirDatabase,
-    display::HirDisplay,
+    display::{DisplayTarget, HirDisplay},
     infer::{Adjustment, TypeMismatch},
     test_db::TestDB,
     InferenceResult, Ty,
@@ -124,7 +124,7 @@ fn check_impl(
     }
     assert!(had_annotations || allow_none, "no `//^` annotations found");
 
-    let mut defs: Vec<DefWithBodyId> = Vec::new();
+    let mut defs: Vec<(DefWithBodyId, CrateId)> = Vec::new();
     for file_id in files {
         let module = db.module_for_file_opt(file_id);
         let module = match module {
@@ -133,16 +133,17 @@ fn check_impl(
         };
         let def_map = module.def_map(&db);
         visit_module(&db, &def_map, module.local_id, &mut |it| {
-            defs.push(match it {
+            let def = match it {
                 ModuleDefId::FunctionId(it) => it.into(),
                 ModuleDefId::EnumVariantId(it) => it.into(),
                 ModuleDefId::ConstId(it) => it.into(),
                 ModuleDefId::StaticId(it) => it.into(),
                 _ => return,
-            })
+            };
+            defs.push((def, module.krate()))
         });
     }
-    defs.sort_by_key(|def| match def {
+    defs.sort_by_key(|(def, _)| match def {
         DefWithBodyId::FunctionId(it) => {
             let loc = it.lookup(&db);
             loc.source(&db).value.syntax().text_range().start()
@@ -162,7 +163,8 @@ fn check_impl(
         DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
     });
     let mut unexpected_type_mismatches = String::new();
-    for def in defs {
+    for (def, krate) in defs {
+        let display_target = DisplayTarget::from_crate(&db, krate);
         let (body, body_source_map) = db.body_with_source_map(def);
         let inference_result = db.infer(def);
 
@@ -179,7 +181,7 @@ fn check_impl(
                 let actual = if display_source {
                     ty.display_source_code(&db, def.module(&db), true).unwrap()
                 } else {
-                    ty.display_test(&db).to_string()
+                    ty.display_test(&db, display_target).to_string()
                 };
                 assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
             }
@@ -195,7 +197,7 @@ fn check_impl(
                 let actual = if display_source {
                     ty.display_source_code(&db, def.module(&db), true).unwrap()
                 } else {
-                    ty.display_test(&db).to_string()
+                    ty.display_test(&db, display_target).to_string()
                 };
                 assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
             }
@@ -224,8 +226,8 @@ fn check_impl(
             let range = node.as_ref().original_file_range_rooted(&db);
             let actual = format!(
                 "expected {}, got {}",
-                mismatch.expected.display_test(&db),
-                mismatch.actual.display_test(&db)
+                mismatch.expected.display_test(&db, display_target),
+                mismatch.actual.display_test(&db, display_target)
             );
             match mismatches.remove(&range) {
                 Some(annotation) => assert_eq!(actual, annotation),
@@ -299,7 +301,9 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
 
     let mut infer_def = |inference_result: Arc<InferenceResult>,
                          body: Arc<Body>,
-                         body_source_map: Arc<BodySourceMap>| {
+                         body_source_map: Arc<BodySourceMap>,
+                         krate: CrateId| {
+        let display_target = DisplayTarget::from_crate(&db, krate);
         let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
         let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new();
 
@@ -361,7 +365,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
                 macro_prefix,
                 range,
                 ellipsize(text, 15),
-                ty.display_test(&db)
+                ty.display_test(&db, display_target)
             );
         }
         if include_mismatches {
@@ -377,8 +381,8 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
                     "{}{:?}: expected {}, got {}\n",
                     macro_prefix,
                     range,
-                    mismatch.expected.display_test(&db),
-                    mismatch.actual.display_test(&db),
+                    mismatch.expected.display_test(&db, display_target),
+                    mismatch.actual.display_test(&db, display_target),
                 );
             }
         }
@@ -387,17 +391,18 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
     let module = db.module_for_file(file_id);
     let def_map = module.def_map(&db);
 
-    let mut defs: Vec<DefWithBodyId> = Vec::new();
+    let mut defs: Vec<(DefWithBodyId, CrateId)> = Vec::new();
     visit_module(&db, &def_map, module.local_id, &mut |it| {
-        defs.push(match it {
+        let def = match it {
             ModuleDefId::FunctionId(it) => it.into(),
             ModuleDefId::EnumVariantId(it) => it.into(),
             ModuleDefId::ConstId(it) => it.into(),
             ModuleDefId::StaticId(it) => it.into(),
             _ => return,
-        })
+        };
+        defs.push((def, module.krate()))
     });
-    defs.sort_by_key(|def| match def {
+    defs.sort_by_key(|(def, _)| match def {
         DefWithBodyId::FunctionId(it) => {
             let loc = it.lookup(&db);
             loc.source(&db).value.syntax().text_range().start()
@@ -416,10 +421,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
         }
         DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
     });
-    for def in defs {
+    for (def, krate) in defs {
         let (body, source_map) = db.body_with_source_map(def);
         let infer = db.infer(def);
-        infer_def(infer, body, source_map);
+        infer_def(infer, body, source_map, krate);
     }
 
     buf.truncate(buf.trim_end().len());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
index 34d299edd1b..6f7bfc4ea7a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
@@ -8,7 +8,7 @@ use syntax::{AstNode, AstPtr};
 use test_fixture::WithFixture;
 
 use crate::db::{HirDatabase, InternedClosureId};
-use crate::display::HirDisplay;
+use crate::display::{DisplayTarget, HirDisplay};
 use crate::mir::MirSpan;
 use crate::test_db::TestDB;
 
@@ -66,7 +66,11 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
                         .join(", "),
                 };
                 let place = capture.display_place(closure.0, db);
-                let capture_ty = capture.ty.skip_binders().display_test(db).to_string();
+                let capture_ty = capture
+                    .ty
+                    .skip_binders()
+                    .display_test(db, DisplayTarget::from_crate(db, module.krate()))
+                    .to_string();
                 let spans = capture
                     .spans()
                     .iter()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 50a1ecd006d..4c5cca21655 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3861,3 +3861,42 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn regression_19196() {
+    check_infer(
+        r#"
+//- minicore: async_fn
+fn async_closure<F: AsyncFnOnce(i32)>(f: F) {}
+fn closure<F: FnOnce(i32)>(f: F) {}
+
+fn main() {
+    async_closure(async |arg| {
+        arg;
+    });
+    closure(|arg| {
+        arg;
+    });
+}
+"#,
+        expect![[r#"
+            38..39 'f': F
+            44..46 '{}': ()
+            74..75 'f': F
+            80..82 '{}': ()
+            94..191 '{     ... }); }': ()
+            100..113 'async_closure': fn async_closure<impl AsyncFnOnce(i32) -> impl Future<Output = ()>>(impl AsyncFnOnce(i32) -> impl Future<Output = ()>)
+            100..147 'async_...    })': ()
+            114..146 'async ...     }': impl AsyncFnOnce(i32) -> impl Future<Output = ()>
+            121..124 'arg': i32
+            126..146 '{     ...     }': ()
+            136..139 'arg': i32
+            153..160 'closure': fn closure<impl FnOnce(i32)>(impl FnOnce(i32))
+            153..188 'closur...    })': ()
+            161..187 '|arg| ...     }': impl FnOnce(i32)
+            162..165 'arg': i32
+            167..187 '{     ...     }': ()
+            177..180 'arg': i32
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
index a34b4980832..372c7252934 100644
--- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
@@ -15,7 +15,7 @@ use tt::TextRange;
 use crate::{
     db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
     InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static,
-    Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant,
+    Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef,
 };
 
 pub trait HasSource {
@@ -110,6 +110,16 @@ impl HasSource for Adt {
         }
     }
 }
+impl HasSource for VariantDef {
+    type Ast = ast::VariantDef;
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        match self {
+            VariantDef::Struct(s) => Some(s.source(db)?.map(ast::VariantDef::Struct)),
+            VariantDef::Union(u) => Some(u.source(db)?.map(ast::VariantDef::Union)),
+            VariantDef::Variant(v) => Some(v.source(db)?.map(ast::VariantDef::Variant)),
+        }
+    }
+}
 impl HasSource for Struct {
     type Ast = ast::Struct;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 55448d4ae86..a8075509474 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -39,7 +39,7 @@ use std::{
 };
 
 use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateId, CrateOrigin};
+use base_db::{CrateDisplayName, CrateId, CrateOrigin, LangCrateOrigin};
 use either::Either;
 use hir_def::{
     data::{adt::VariantData, TraitFlags},
@@ -139,6 +139,7 @@ pub use {
         },
         hygiene::{marks_rev, SyntaxContextExt},
         inert_attr_macro::AttributeTemplate,
+        mod_path::tool_path,
         name::Name,
         prettify_macro_expansion,
         proc_macro::{ProcMacros, ProcMacrosBuilder},
@@ -147,7 +148,7 @@ pub use {
     hir_ty::{
         consteval::ConstEvalError,
         diagnostics::UnsafetyReason,
-        display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
+        display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite},
         dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode},
         layout::LayoutError,
         method_resolution::TyFingerprint,
@@ -282,6 +283,21 @@ impl Crate {
         let data = &db.crate_graph()[self.id];
         data.potential_cfg_options.clone().unwrap_or_else(|| data.cfg_options.clone())
     }
+
+    pub fn to_display_target(self, db: &dyn HirDatabase) -> DisplayTarget {
+        DisplayTarget::from_crate(db, self.id)
+    }
+
+    fn core(db: &dyn HirDatabase) -> Option<Crate> {
+        let crate_graph = db.crate_graph();
+        let result = crate_graph
+            .iter()
+            .find(|&krate| {
+                matches!(crate_graph[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core))
+            })
+            .map(Crate::from);
+        result
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -296,6 +312,7 @@ pub enum ModuleDef {
     Function(Function),
     Adt(Adt),
     // Can't be directly declared, but can be imported.
+    // FIXME: Rename to `EnumVariant`
     Variant(Variant),
     Const(Const),
     Static(Static),
@@ -469,6 +486,17 @@ impl ModuleDef {
     }
 }
 
+impl HasCrate for ModuleDef {
+    fn krate(&self, db: &dyn HirDatabase) -> Crate {
+        match self.module(db) {
+            Some(module) => module.krate(),
+            None => Crate::core(db).unwrap_or_else(|| {
+                (*db.crate_graph().crates_in_topological_order().last().unwrap()).into()
+            }),
+        }
+    }
+}
+
 impl HasVisibility for ModuleDef {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         match *self {
@@ -1564,6 +1592,7 @@ impl From<&Variant> for DefWithBodyId {
     }
 }
 
+// FIXME: Rename to `EnumVariant`
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Variant {
     pub(crate) id: EnumVariantId,
@@ -1863,7 +1892,7 @@ impl DefWithBody {
     pub fn debug_mir(self, db: &dyn HirDatabase) -> String {
         let body = db.mir_body(self.id());
         match body {
-            Ok(body) => body.pretty_print(db),
+            Ok(body) => body.pretty_print(db, self.module(db).krate().to_display_target(db)),
             Err(e) => format!("error:\n{e:?}"),
         }
     }
@@ -2449,8 +2478,6 @@ impl Function {
         db: &dyn HirDatabase,
         span_formatter: impl Fn(FileId, TextRange) -> String,
     ) -> Result<String, ConstEvalError> {
-        let krate = HasModule::krate(&self.id, db.upcast());
-        let edition = db.crate_graph()[krate].edition;
         let body = db.monomorphized_mir_body(
             self.id.into(),
             Substitution::empty(Interner),
@@ -2461,7 +2488,12 @@ impl Function {
             Ok(_) => "pass".to_owned(),
             Err(e) => {
                 let mut r = String::new();
-                _ = e.pretty_print(&mut r, db, &span_formatter, edition);
+                _ = e.pretty_print(
+                    &mut r,
+                    db,
+                    &span_formatter,
+                    self.krate(db).to_display_target(db),
+                );
                 r
             }
         };
@@ -2725,8 +2757,8 @@ pub struct EvaluatedConst {
 }
 
 impl EvaluatedConst {
-    pub fn render(&self, db: &dyn HirDatabase, edition: Edition) -> String {
-        format!("{}", self.const_.display(db, edition))
+    pub fn render(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
+        format!("{}", self.const_.display(db, display_target))
     }
 
     pub fn render_debug(&self, db: &dyn HirDatabase) -> Result<String, MirEvalError> {
@@ -4195,9 +4227,13 @@ impl ConstParam {
         Type::new(db, self.id.parent(), db.const_param_ty(self.id))
     }
 
-    pub fn default(self, db: &dyn HirDatabase, edition: Edition) -> Option<ast::ConstArg> {
+    pub fn default(
+        self,
+        db: &dyn HirDatabase,
+        display_target: DisplayTarget,
+    ) -> Option<ast::ConstArg> {
         let arg = generic_arg_from_param(db, self.id.into())?;
-        known_const_to_ast(arg.constant(Interner)?, db, edition)
+        known_const_to_ast(arg.constant(Interner)?, db, display_target)
     }
 }
 
@@ -4505,18 +4541,18 @@ impl Closure {
         TyKind::Closure(self.id, self.subst).intern(Interner)
     }
 
-    pub fn display_with_id(&self, db: &dyn HirDatabase, edition: Edition) -> String {
+    pub fn display_with_id(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
         self.clone()
             .as_ty()
-            .display(db, edition)
+            .display(db, display_target)
             .with_closure_style(ClosureStyle::ClosureWithId)
             .to_string()
     }
 
-    pub fn display_with_impl(&self, db: &dyn HirDatabase, edition: Edition) -> String {
+    pub fn display_with_impl(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
         self.clone()
             .as_ty()
-            .display(db, edition)
+            .display(db, display_target)
             .with_closure_style(ClosureStyle::ImplFn)
             .to_string()
     }
@@ -5321,7 +5357,7 @@ impl Type {
     pub fn type_and_const_arguments<'a>(
         &'a self,
         db: &'a dyn HirDatabase,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> impl Iterator<Item = SmolStr> + 'a {
         self.ty
             .strip_references()
@@ -5331,10 +5367,10 @@ impl Type {
             .filter_map(move |arg| {
                 // arg can be either a `Ty` or `constant`
                 if let Some(ty) = arg.ty(Interner) {
-                    Some(format_smolstr!("{}", ty.display(db, edition)))
+                    Some(format_smolstr!("{}", ty.display(db, display_target)))
                 } else {
                     arg.constant(Interner)
-                        .map(|const_| format_smolstr!("{}", const_.display(db, edition)))
+                        .map(|const_| format_smolstr!("{}", const_.display(db, display_target)))
                 }
             })
     }
@@ -5343,7 +5379,7 @@ impl Type {
     pub fn generic_parameters<'a>(
         &'a self,
         db: &'a dyn HirDatabase,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> impl Iterator<Item = SmolStr> + 'a {
         // iterate the lifetime
         self.as_adt()
@@ -5353,7 +5389,7 @@ impl Type {
             })
             .into_iter()
             // add the type and const parameters
-            .chain(self.type_and_const_arguments(db, edition))
+            .chain(self.type_and_const_arguments(db, display_target))
     }
 
     pub fn iterate_method_candidates_with_traits<T>(
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index bb67fa63a1d..5e2eebcd13c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -12,7 +12,8 @@ use std::{
 
 use either::Either;
 use hir_def::{
-    hir::{Expr, ExprOrPatId},
+    expr_store::{Body, ExprOrPatSource},
+    hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
     lower::LowerCtx,
     nameres::{MacroSubNs, ModuleOrigin},
     path::ModPath,
@@ -30,6 +31,7 @@ use hir_expand::{
     name::AsName,
     ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
 };
+use hir_ty::diagnostics::unsafe_operations_for_body;
 use intern::{sym, Symbol};
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -48,8 +50,8 @@ use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
-    Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
-    ConstParam, Crate, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource,
+    Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam,
+    Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource,
     HirFileId, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
     Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait,
     TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
@@ -311,6 +313,14 @@ impl<'db> SemanticsImpl<'db> {
         tree
     }
 
+    /// If not crate is found for the file, returns the last crate in topological order.
+    pub fn first_crate_or_default(&self, file: FileId) -> Crate {
+        match self.file_to_module_defs(file).next() {
+            Some(module) => module.krate(),
+            None => (*self.db.crate_graph().crates_in_topological_order().last().unwrap()).into(),
+        }
+    }
+
     pub fn attach_first_edition(&self, file: FileId) -> Option<EditionedFileId> {
         Some(EditionedFileId::new(
             file,
@@ -627,6 +637,31 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
+    /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals,
+    /// and returns the conflicting locals.
+    pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &str) -> Vec<Local> {
+        let body = self.db.body(to_be_renamed.parent);
+        let resolver = to_be_renamed.parent.resolver(self.db.upcast());
+        let starting_expr =
+            body.binding_owners.get(&to_be_renamed.binding_id).copied().unwrap_or(body.body_expr);
+        let mut visitor = RenameConflictsVisitor {
+            body: &body,
+            conflicts: FxHashSet::default(),
+            db: self.db,
+            new_name: Symbol::intern(new_name),
+            old_name: to_be_renamed.name(self.db).symbol().clone(),
+            owner: to_be_renamed.parent,
+            to_be_renamed: to_be_renamed.binding_id,
+            resolver,
+        };
+        visitor.rename_conflicts(starting_expr);
+        visitor
+            .conflicts
+            .into_iter()
+            .map(|binding_id| Local { parent: to_be_renamed.parent, binding_id })
+            .collect()
+    }
+
     /// Retrieves all the formatting parts of the format_args! (or `asm!`) template string.
     pub fn as_format_args_parts(
         &self,
@@ -1555,6 +1590,19 @@ impl<'db> SemanticsImpl<'db> {
             .matched_arm
     }
 
+    pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> {
+        let def = DefWithBodyId::from(def);
+        let (body, source_map) = self.db.body_with_source_map(def);
+        let infer = self.db.infer(def);
+        let mut res = FxHashSet::default();
+        unsafe_operations_for_body(self.db, &infer, def, &body, &mut |node| {
+            if let Ok(node) = source_map.expr_or_pat_syntax(node) {
+                res.insert(node);
+            }
+        });
+        res
+    }
+
     pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
         let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
         if mac.is_asm_or_global_asm(self.db) {
@@ -1682,6 +1730,15 @@ impl<'db> SemanticsImpl<'db> {
         Some(res)
     }
 
+    pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
+        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
+
+        match container {
+            ChildContainer::DefWithBodyId(def) => Some(def.into()),
+            _ => None,
+        }
+    }
+
     /// Returns none if the file of the node is not part of a crate.
     fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
         let node = self.find_file(node);
@@ -1783,91 +1840,6 @@ impl<'db> SemanticsImpl<'db> {
         InFile::new(file_id, node)
     }
 
-    pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
-        method_call_expr
-            .receiver()
-            .and_then(|expr| {
-                let field_expr = match expr {
-                    ast::Expr::FieldExpr(field_expr) => field_expr,
-                    _ => return None,
-                };
-                let ty = self.type_of_expr(&field_expr.expr()?)?.original;
-                if !ty.is_packed(self.db) {
-                    return None;
-                }
-
-                let func = self.resolve_method_call(method_call_expr)?;
-                let res = match func.self_param(self.db)?.access(self.db) {
-                    Access::Shared | Access::Exclusive => true,
-                    Access::Owned => false,
-                };
-                Some(res)
-            })
-            .unwrap_or(false)
-    }
-
-    pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
-        ref_expr
-            .expr()
-            .and_then(|expr| {
-                let field_expr = match expr {
-                    ast::Expr::FieldExpr(field_expr) => field_expr,
-                    _ => return None,
-                };
-                let expr = field_expr.expr()?;
-                self.type_of_expr(&expr)
-            })
-            // Binding a reference to a packed type is possibly unsafe.
-            .map(|ty| ty.original.is_packed(self.db))
-            .unwrap_or(false)
-
-        // FIXME This needs layout computation to be correct. It will highlight
-        // more than it should with the current implementation.
-    }
-
-    pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
-        if ident_pat.ref_token().is_none() {
-            return false;
-        }
-
-        ident_pat
-            .syntax()
-            .parent()
-            .and_then(|parent| {
-                // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
-                // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
-                // so this tries to lookup the `IdentPat` anywhere along that structure to the
-                // `RecordPat` so we can get the containing type.
-                let record_pat = ast::RecordPatField::cast(parent.clone())
-                    .and_then(|record_pat| record_pat.syntax().parent())
-                    .or_else(|| Some(parent.clone()))
-                    .and_then(|parent| {
-                        ast::RecordPatFieldList::cast(parent)?
-                            .syntax()
-                            .parent()
-                            .and_then(ast::RecordPat::cast)
-                    });
-
-                // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
-                // this is initialized from a `FieldExpr`.
-                if let Some(record_pat) = record_pat {
-                    self.type_of_pat(&ast::Pat::RecordPat(record_pat))
-                } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
-                    let field_expr = match let_stmt.initializer()? {
-                        ast::Expr::FieldExpr(field_expr) => field_expr,
-                        _ => return None,
-                    };
-
-                    self.type_of_expr(&field_expr.expr()?)
-                } else {
-                    None
-                }
-            })
-            // Binding a reference to a packed type is possibly unsafe.
-            .map(|ty| ty.original.is_packed(self.db))
-            .unwrap_or(false)
-    }
-
     /// Returns `true` if the `node` is inside an `unsafe` context.
     pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
         let Some(enclosing_item) =
@@ -2155,3 +2127,69 @@ impl ops::Deref for VisibleTraits {
         &self.0
     }
 }
+
+struct RenameConflictsVisitor<'a> {
+    db: &'a dyn HirDatabase,
+    owner: DefWithBodyId,
+    resolver: Resolver,
+    body: &'a Body,
+    to_be_renamed: BindingId,
+    new_name: Symbol,
+    old_name: Symbol,
+    conflicts: FxHashSet<BindingId>,
+}
+
+impl RenameConflictsVisitor<'_> {
+    fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) {
+        if let Path::BarePath(path) = path {
+            if let Some(name) = path.as_ident() {
+                if *name.symbol() == self.new_name {
+                    if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
+                        self.db.upcast(),
+                        name,
+                        path,
+                        self.body.expr_or_pat_path_hygiene(node),
+                        self.to_be_renamed,
+                    ) {
+                        self.conflicts.insert(conflicting);
+                    }
+                } else if *name.symbol() == self.old_name {
+                    if let Some(conflicting) =
+                        self.resolver.rename_will_conflict_with_another_variable(
+                            self.db.upcast(),
+                            name,
+                            path,
+                            self.body.expr_or_pat_path_hygiene(node),
+                            &self.new_name,
+                            self.to_be_renamed,
+                        )
+                    {
+                        self.conflicts.insert(conflicting);
+                    }
+                }
+            }
+        }
+    }
+
+    fn rename_conflicts(&mut self, expr: ExprId) {
+        match &self.body[expr] {
+            Expr::Path(path) => {
+                let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
+                self.resolve_path(expr.into(), path);
+                self.resolver.reset_to_guard(guard);
+            }
+            &Expr::Assignment { target, .. } => {
+                let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
+                self.body.walk_pats(target, &mut |pat| {
+                    if let Pat::Path(path) = &self.body[pat] {
+                        self.resolve_path(pat.into(), path);
+                    }
+                });
+                self.resolver.reset_to_guard(guard);
+            }
+            _ => {}
+        }
+
+        self.body.walk_child_exprs(expr, |expr| self.rename_conflicts(expr));
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 9019863f7fd..d1245f5f7d6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -35,7 +35,7 @@ use hir_expand::{
 };
 use hir_ty::{
     diagnostics::{
-        record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
+        record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations,
         InsideUnsafeBlock,
     },
     from_assoc_type_id,
@@ -1160,7 +1160,7 @@ impl SourceAnalyzer {
             if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
                 let mut is_unsafe = false;
                 let mut walk_expr = |expr_id| {
-                    unsafe_expressions(db, infer, *def, body, expr_id, &mut |inside_unsafe_block| {
+                    unsafe_operations(db, infer, *def, body, expr_id, &mut |inside_unsafe_block| {
                         is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
                     })
                 };
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index 2ebd88edae2..81eb6a70ad7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -13,11 +13,10 @@ use hir_def::{
 use hir_expand::{name::Name, HirFileId};
 use hir_ty::{
     db::HirDatabase,
-    display::{hir_display_with_types_map, HirDisplay},
+    display::{hir_display_with_types_map, DisplayTarget, HirDisplay},
 };
 use intern::Symbol;
 use rustc_hash::FxHashMap;
-use span::Edition;
 use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
 
 use crate::{Module, ModuleDef, Semantics};
@@ -66,7 +65,7 @@ pub struct SymbolCollector<'a> {
     symbols: FxIndexSet<FileSymbol>,
     work: Vec<SymbolCollectorWork>,
     current_container_name: Option<SmolStr>,
-    edition: Edition,
+    display_target: DisplayTarget,
 }
 
 /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect
@@ -78,7 +77,10 @@ impl<'a> SymbolCollector<'a> {
             symbols: Default::default(),
             work: Default::default(),
             current_container_name: None,
-            edition: Edition::Edition2015,
+            display_target: DisplayTarget::from_crate(
+                db,
+                *db.crate_graph().crates_in_topological_order().last().unwrap(),
+            ),
         }
     }
 
@@ -91,7 +93,7 @@ impl<'a> SymbolCollector<'a> {
     pub fn collect(&mut self, module: Module) {
         let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered();
         tracing::info!(?module, "SymbolCollector::collect",);
-        self.edition = module.krate().edition(self.db);
+        self.display_target = module.krate().to_display_target(self.db);
 
         // The initial work is the root module we're collecting, additional work will
         // be populated as we traverse the module's definitions.
@@ -307,7 +309,7 @@ impl<'a> SymbolCollector<'a> {
         let impl_data = self.db.impl_data(impl_id);
         let impl_name = Some(
             hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map)
-                .display(self.db, self.edition)
+                .display(self.db, self.display_target)
                 .to_smolstr(),
         );
         self.with_container_name(impl_name, |s| {
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
index d2070f0e18b..0d672dc332f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -4,7 +4,7 @@ use hir_def::ImportPathConfig;
 use hir_expand::mod_path::ModPath;
 use hir_ty::{
     db::HirDatabase,
-    display::{DisplaySourceCodeError, HirDisplay},
+    display::{DisplaySourceCodeError, DisplayTarget, HirDisplay},
 };
 use itertools::Itertools;
 use span::Edition;
@@ -99,14 +99,16 @@ impl Expr {
         sema_scope: &SemanticsScope<'_>,
         many_formatter: &mut dyn FnMut(&Type) -> String,
         cfg: ImportPathConfig,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> Result<String, DisplaySourceCodeError> {
         let db = sema_scope.db;
+        let edition = display_target.edition;
         let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg, edition);
         match self {
             Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) {
                 Some(container) => {
-                    let container_name = container_name(container, sema_scope, cfg, edition)?;
+                    let container_name =
+                        container_name(container, sema_scope, cfg, edition, display_target)?;
                     let const_name = it
                         .name(db)
                         .map(|c| c.display(db.upcast(), edition).to_string())
@@ -122,14 +124,15 @@ impl Expr {
             Expr::Function { func, params, .. } => {
                 let args = params
                     .iter()
-                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
+                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, display_target))
                     .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                     .into_iter()
                     .join(", ");
 
                 match func.as_assoc_item(db).map(|it| it.container(db)) {
                     Some(container) => {
-                        let container_name = container_name(container, sema_scope, cfg, edition)?;
+                        let container_name =
+                            container_name(container, sema_scope, cfg, edition, display_target)?;
                         let fn_name = func.name(db).display(db.upcast(), edition).to_string();
                         Ok(format!("{container_name}::{fn_name}({args})"))
                     }
@@ -147,10 +150,10 @@ impl Expr {
                 let func_name = func.name(db).display(db.upcast(), edition).to_string();
                 let self_param = func.self_param(db).unwrap();
                 let target_str =
-                    target.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
+                    target.gen_source_code(sema_scope, many_formatter, cfg, display_target)?;
                 let args = params
                     .iter()
-                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
+                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, display_target))
                     .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                     .into_iter()
                     .join(", ");
@@ -180,7 +183,9 @@ impl Expr {
                     StructKind::Tuple => {
                         let args = params
                             .iter()
-                            .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
+                            .map(|f| {
+                                f.gen_source_code(sema_scope, many_formatter, cfg, display_target)
+                            })
                             .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                             .into_iter()
                             .join(", ");
@@ -195,7 +200,12 @@ impl Expr {
                                 let tmp = format!(
                                     "{}: {}",
                                     f.name(db).display(db.upcast(), edition),
-                                    a.gen_source_code(sema_scope, many_formatter, cfg, edition)?
+                                    a.gen_source_code(
+                                        sema_scope,
+                                        many_formatter,
+                                        cfg,
+                                        display_target
+                                    )?
                                 );
                                 Ok(tmp)
                             })
@@ -215,7 +225,9 @@ impl Expr {
                     StructKind::Tuple => {
                         let args = params
                             .iter()
-                            .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition))
+                            .map(|a| {
+                                a.gen_source_code(sema_scope, many_formatter, cfg, display_target)
+                            })
                             .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                             .into_iter()
                             .join(", ");
@@ -230,7 +242,12 @@ impl Expr {
                                 let tmp = format!(
                                     "{}: {}",
                                     f.name(db).display(db.upcast(), edition),
-                                    a.gen_source_code(sema_scope, many_formatter, cfg, edition)?
+                                    a.gen_source_code(
+                                        sema_scope,
+                                        many_formatter,
+                                        cfg,
+                                        display_target
+                                    )?
                                 );
                                 Ok(tmp)
                             })
@@ -248,7 +265,7 @@ impl Expr {
             Expr::Tuple { params, .. } => {
                 let args = params
                     .iter()
-                    .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition))
+                    .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, display_target))
                     .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                     .into_iter()
                     .join(", ");
@@ -260,7 +277,8 @@ impl Expr {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
-                let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
+                let strukt =
+                    expr.gen_source_code(sema_scope, many_formatter, cfg, display_target)?;
                 let field = field.name(db).display(db.upcast(), edition).to_string();
                 Ok(format!("{strukt}.{field}"))
             }
@@ -269,7 +287,8 @@ impl Expr {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
-                let inner = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
+                let inner =
+                    expr.gen_source_code(sema_scope, many_formatter, cfg, display_target)?;
                 Ok(format!("&{inner}"))
             }
             Expr::Many(ty) => Ok(many_formatter(ty)),
@@ -358,6 +377,7 @@ fn container_name(
     sema_scope: &SemanticsScope<'_>,
     cfg: ImportPathConfig,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Result<String, DisplaySourceCodeError> {
     let container_name = match container {
         crate::AssocItemContainer::Trait(trait_) => {
@@ -368,7 +388,7 @@ fn container_name(
             // Should it be guaranteed that `mod_item_path` always exists?
             match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) {
                 Some(path) => path.display(sema_scope.db.upcast(), edition).to_string(),
-                None => self_ty.display(sema_scope.db, edition).to_string(),
+                None => self_ty.display(sema_scope.db, display_target).to_string(),
             }
         }
     };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
index fafc3448a87..1a5de9cb071 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
@@ -8,7 +8,7 @@ use syntax::{ast, AstNode};
 
 use crate::{AssistContext, Assists};
 
-// Assist: explicit_enum_discriminant
+// Assist: add_explicit_enum_discriminant
 //
 // Adds explicit discriminant to all enum variants.
 //
@@ -29,7 +29,10 @@ use crate::{AssistContext, Assists};
 //     Quux = 43,
 // }
 // ```
-pub(crate) fn explicit_enum_discriminant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+pub(crate) fn add_explicit_enum_discriminant(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
     let enum_node = ctx.find_node_at_offset::<ast::Enum>()?;
     let enum_def = ctx.sema.to_def(&enum_node)?;
 
@@ -50,7 +53,7 @@ pub(crate) fn explicit_enum_discriminant(acc: &mut Assists, ctx: &AssistContext<
     }
 
     acc.add(
-        AssistId("explicit_enum_discriminant", AssistKind::RefactorRewrite),
+        AssistId("add_explicit_enum_discriminant", AssistKind::RefactorRewrite),
         "Add explicit enum discriminants",
         enum_node.syntax().text_range(),
         |builder| {
@@ -88,12 +91,12 @@ fn add_variant_discriminant(
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
 
-    use super::explicit_enum_discriminant;
+    use super::add_explicit_enum_discriminant;
 
     #[test]
     fn non_primitive_repr_non_data_bearing_add_discriminant() {
         check_assist(
-            explicit_enum_discriminant,
+            add_explicit_enum_discriminant,
             r#"
 enum TheEnum$0 {
     Foo,
@@ -120,7 +123,7 @@ enum TheEnum {
     #[test]
     fn primitive_repr_data_bearing_add_discriminant() {
         check_assist(
-            explicit_enum_discriminant,
+            add_explicit_enum_discriminant,
             r#"
 #[repr(u8)]
 $0enum TheEnum {
@@ -145,7 +148,7 @@ enum TheEnum {
     #[test]
     fn non_primitive_repr_data_bearing_not_applicable() {
         check_assist_not_applicable(
-            explicit_enum_discriminant,
+            add_explicit_enum_discriminant,
             r#"
 enum TheEnum$0 {
     Foo,
@@ -159,7 +162,7 @@ enum TheEnum$0 {
     #[test]
     fn primitive_repr_non_data_bearing_add_discriminant() {
         check_assist(
-            explicit_enum_discriminant,
+            add_explicit_enum_discriminant,
             r#"
 #[repr(i64)]
 enum TheEnum {
@@ -184,7 +187,7 @@ enum TheEnum {
     #[test]
     fn discriminants_already_explicit_not_applicable() {
         check_assist_not_applicable(
-            explicit_enum_discriminant,
+            add_explicit_enum_discriminant,
             r#"
 enum TheEnum$0 {
     Foo = 0,
@@ -197,7 +200,7 @@ enum TheEnum$0 {
     #[test]
     fn empty_enum_not_applicable() {
         check_assist_not_applicable(
-            explicit_enum_discriminant,
+            add_explicit_enum_discriminant,
             r#"
 enum TheEnum$0 {}
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 77562c588e2..67bf8eed23d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -128,7 +128,9 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
                     let parent = neg_expr.syntax().parent();
                     editor = builder.make_editor(neg_expr.syntax());
 
-                    if parent.is_some_and(|parent| demorganed.needs_parens_in(&parent)) {
+                    if parent.is_some_and(|parent| {
+                        demorganed.needs_parens_in_place_of(&parent, neg_expr.syntax())
+                    }) {
                         cov_mark::hit!(demorgan_keep_parens_for_op_precedence2);
                         editor.replace(neg_expr.syntax(), make.expr_paren(demorganed).syntax());
                     } else {
@@ -392,15 +394,19 @@ fn f() { !(S <= S || S < S) }
 
     #[test]
     fn demorgan_keep_pars_for_op_precedence3() {
-        check_assist(apply_demorgan, "fn f() { (a || !(b &&$0 c); }", "fn f() { (a || !b || !c; }");
+        check_assist(
+            apply_demorgan,
+            "fn f() { (a || !(b &&$0 c); }",
+            "fn f() { (a || (!b || !c); }",
+        );
     }
 
     #[test]
-    fn demorgan_removes_pars_in_eq_precedence() {
+    fn demorgan_keeps_pars_in_eq_precedence() {
         check_assist(
             apply_demorgan,
             "fn() { let x = a && !(!b |$0| !c); }",
-            "fn() { let x = a && b && c; }",
+            "fn() { let x = a && (b && c); }",
         )
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
index cbd39796241..7716e99e604 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
@@ -26,7 +26,7 @@ use crate::{
     utils,
 };
 
-// Assist: bool_to_enum
+// Assist: convert_bool_to_enum
 //
 // This converts boolean local variables, fields, constants, and statics into a new
 // enum with two variants `Bool::True` and `Bool::False`, as well as replacing
@@ -55,14 +55,14 @@ use crate::{
 //     }
 // }
 // ```
-pub(crate) fn bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let BoolNodeData { target_node, name, ty_annotation, initializer, definition } =
         find_bool_node(ctx)?;
     let target_module = ctx.sema.scope(&target_node)?.module().nearest_non_block_module(ctx.db());
 
     let target = name.syntax().text_range();
     acc.add(
-        AssistId("bool_to_enum", AssistKind::RefactorRewrite),
+        AssistId("convert_bool_to_enum", AssistKind::RefactorRewrite),
         "Convert boolean to enum",
         target,
         |edit| {
@@ -549,7 +549,7 @@ mod tests {
     #[test]
     fn parameter_with_first_param_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn function($0foo: bool, bar: bool) {
     if foo {
@@ -573,7 +573,7 @@ fn function(foo: Bool, bar: bool) {
     #[test]
     fn no_duplicate_enums() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 #[derive(PartialEq, Eq)]
 enum Bool { True, False }
@@ -600,7 +600,7 @@ fn function(foo: bool, bar: Bool) {
     #[test]
     fn parameter_with_last_param_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn function(foo: bool, $0bar: bool) {
     if bar {
@@ -624,7 +624,7 @@ fn function(foo: bool, bar: Bool) {
     #[test]
     fn parameter_with_middle_param_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn function(foo: bool, $0bar: bool, baz: bool) {
     if bar {
@@ -648,7 +648,7 @@ fn function(foo: bool, bar: Bool, baz: bool) {
     #[test]
     fn parameter_with_closure_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let foo = |$0bar: bool| bar;
@@ -668,7 +668,7 @@ fn main() {
     #[test]
     fn local_variable_with_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = true;
@@ -697,7 +697,7 @@ fn main() {
     fn local_variable_with_usage_negated() {
         cov_mark::check!(replaces_negation);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = true;
@@ -726,7 +726,7 @@ fn main() {
     fn local_variable_with_type_annotation() {
         cov_mark::check!(replaces_ty_annotation);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo: bool = false;
@@ -746,7 +746,7 @@ fn main() {
     #[test]
     fn local_variable_with_non_literal_initializer() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = 1 == 2;
@@ -766,7 +766,7 @@ fn main() {
     #[test]
     fn local_variable_binexpr_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = false;
@@ -796,7 +796,7 @@ fn main() {
     #[test]
     fn local_variable_unop_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = true;
@@ -825,7 +825,7 @@ fn main() {
     fn local_variable_assigned_later() {
         cov_mark::check!(replaces_assignment);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo: bool;
@@ -847,7 +847,7 @@ fn main() {
     #[test]
     fn local_variable_does_not_apply_recursively() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = true;
@@ -878,7 +878,7 @@ fn main() {
     fn local_variable_nested_in_negation() {
         cov_mark::check!(dont_overwrite_expression_inside_negation);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     if !"foo".chars().any(|c| {
@@ -909,7 +909,7 @@ fn main() {
     fn local_variable_non_bool() {
         cov_mark::check!(not_applicable_non_bool_local);
         check_assist_not_applicable(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let $0foo = 1;
@@ -921,7 +921,7 @@ fn main() {
     #[test]
     fn local_variable_cursor_not_on_ident() {
         check_assist_not_applicable(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let foo = $0true;
@@ -933,7 +933,7 @@ fn main() {
     #[test]
     fn local_variable_non_ident_pat() {
         check_assist_not_applicable(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     let ($0foo, bar) = (true, false);
@@ -945,7 +945,7 @@ fn main() {
     #[test]
     fn local_var_init_struct_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     foo: bool,
@@ -975,7 +975,7 @@ fn main() {
     #[test]
     fn local_var_init_struct_usage_in_macro() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Struct {
     boolean: bool,
@@ -1018,7 +1018,7 @@ fn new() -> Struct {
     fn field_struct_basic() {
         cov_mark::check!(replaces_record_expr);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0bar: bool,
@@ -1057,7 +1057,7 @@ fn main() {
     fn field_enum_basic() {
         cov_mark::check!(replaces_record_pat);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 enum Foo {
     Foo,
@@ -1100,7 +1100,7 @@ fn main() {
     fn field_enum_cross_file() {
         // FIXME: The import is missing
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 //- /foo.rs
 pub enum Foo {
@@ -1151,7 +1151,7 @@ fn main() {
     fn field_enum_shorthand() {
         cov_mark::check!(replaces_record_pat_shorthand);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 enum Foo {
     Foo,
@@ -1200,7 +1200,7 @@ fn main() {
     fn field_enum_replaces_literal_patterns() {
         cov_mark::check!(replaces_literal_pat);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 enum Foo {
     Foo,
@@ -1238,7 +1238,7 @@ fn main() {
     #[test]
     fn field_enum_keeps_wildcard_patterns() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 enum Foo {
     Foo,
@@ -1276,7 +1276,7 @@ fn main() {
     #[test]
     fn field_union_basic() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 union Foo {
     $0foo: bool,
@@ -1314,7 +1314,7 @@ fn main() {
     #[test]
     fn field_negated() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0bar: bool,
@@ -1350,7 +1350,7 @@ fn main() {
     #[test]
     fn field_in_mod_properly_indented() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 mod foo {
     struct Bar {
@@ -1386,7 +1386,7 @@ mod foo {
     #[test]
     fn field_multiple_initializations() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0bar: bool,
@@ -1427,7 +1427,7 @@ fn main() {
     fn field_assigned_to_another() {
         cov_mark::check!(dont_assign_incorrect_ref);
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0foo: bool,
@@ -1469,7 +1469,7 @@ fn main() {
     #[test]
     fn field_initialized_with_other() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0foo: bool,
@@ -1507,7 +1507,7 @@ fn main() {
     #[test]
     fn field_method_chain_usage() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0bool: bool,
@@ -1539,7 +1539,7 @@ fn main() {
     #[test]
     fn field_in_macro() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Struct {
     $0boolean: bool,
@@ -1580,7 +1580,7 @@ fn new() -> Struct {
     fn field_non_bool() {
         cov_mark::check!(not_applicable_non_bool_field);
         check_assist_not_applicable(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 struct Foo {
     $0bar: usize,
@@ -1596,7 +1596,7 @@ fn main() {
     #[test]
     fn const_basic() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 const $0FOO: bool = false;
 
@@ -1624,7 +1624,7 @@ fn main() {
     #[test]
     fn const_in_module() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     if foo::FOO {
@@ -1658,7 +1658,7 @@ mod foo {
     #[test]
     fn const_in_module_with_import() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 fn main() {
     use foo::FOO;
@@ -1696,7 +1696,7 @@ mod foo {
     #[test]
     fn const_cross_file() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 //- /main.rs
 mod foo;
@@ -1734,7 +1734,7 @@ pub const FOO: Bool = Bool::True;
     #[test]
     fn const_cross_file_and_module() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 //- /main.rs
 mod foo;
@@ -1780,7 +1780,7 @@ pub mod bar {
     #[test]
     fn const_in_impl_cross_file() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 //- /main.rs
 mod foo;
@@ -1824,7 +1824,7 @@ fn foo() -> bool {
     #[test]
     fn const_in_trait() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 trait Foo {
     const $0BOOL: bool;
@@ -1865,7 +1865,7 @@ fn main() {
     fn const_non_bool() {
         cov_mark::check!(not_applicable_non_bool_const);
         check_assist_not_applicable(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 const $0FOO: &str = "foo";
 
@@ -1879,7 +1879,7 @@ fn main() {
     #[test]
     fn static_basic() {
         check_assist(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 static mut $0BOOL: bool = true;
 
@@ -1910,7 +1910,7 @@ fn main() {
     fn static_non_bool() {
         cov_mark::check!(not_applicable_non_bool_static);
         check_assist_not_applicable(
-            bool_to_enum,
+            convert_bool_to_enum,
             r#"
 static mut $0FOO: usize = 0;
 
@@ -1925,6 +1925,6 @@ fn main() {
 
     #[test]
     fn not_applicable_to_other_names() {
-        check_assist_not_applicable(bool_to_enum, "fn $0main() {}")
+        check_assist_not_applicable(convert_bool_to_enum, "fn $0main() {}")
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
index ee321864805..c79a982c38d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
@@ -1,11 +1,29 @@
+use hir::{PathResolution, StructKind};
+use ide_db::syntax_helpers::suggest_name::NameGenerator;
 use syntax::{
     ast::{self, make},
-    AstNode, ToSmolStr,
+    match_ast, AstNode, ToSmolStr,
 };
 
 use crate::{AssistContext, AssistId, Assists};
 
-// Assist: fill_record_pattern_fields
+pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let rest_pat = ctx.find_node_at_offset::<ast::RestPat>()?;
+    let parent = rest_pat.syntax().parent()?;
+    match_ast! {
+        match parent {
+            ast::RecordPatFieldList(it) => expand_record_rest_pattern(acc, ctx, it.syntax().parent().and_then(ast::RecordPat::cast)?, rest_pat),
+            ast::TupleStructPat(it) => expand_tuple_struct_rest_pattern(acc, ctx, it, rest_pat),
+            // FIXME
+            // ast::TuplePat(it) => (),
+            // FIXME
+            // ast::SlicePat(it) => (),
+            _ => return None,
+        }
+    }
+}
+
+// Assist: expand_record_rest_pattern
 //
 // Fills fields by replacing rest pattern in record patterns.
 //
@@ -24,16 +42,12 @@ use crate::{AssistContext, AssistId, Assists};
 //     let Bar { y, z  } = bar;
 // }
 // ```
-pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let record_pat = ctx.find_node_at_offset::<ast::RecordPat>()?;
-
-    let ellipsis = record_pat.record_pat_field_list().and_then(|r| r.rest_pat())?;
-    if !ellipsis.syntax().text_range().contains_inclusive(ctx.offset()) {
-        return None;
-    }
-
-    let target_range = ellipsis.syntax().text_range();
-
+fn expand_record_rest_pattern(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+    record_pat: ast::RecordPat,
+    rest_pat: ast::RestPat,
+) -> Option<()> {
     let missing_fields = ctx.sema.record_pattern_missing_fields(&record_pat);
 
     if missing_fields.is_empty() {
@@ -42,6 +56,11 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext<
     }
 
     let old_field_list = record_pat.record_pat_field_list()?;
+    let old_range = ctx.sema.original_range_opt(old_field_list.syntax())?;
+    if old_range.file_id != ctx.file_id() {
+        return None;
+    }
+
     let new_field_list =
         make::record_pat_field_list(old_field_list.fields(), None).clone_for_update();
     for (f, _) in missing_fields.iter() {
@@ -52,16 +71,93 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext<
         new_field_list.add_field(field.clone_for_update());
     }
 
-    let old_range = ctx.sema.original_range_opt(old_field_list.syntax())?;
+    let target_range = rest_pat.syntax().text_range();
+    acc.add(
+        AssistId("expand_record_rest_pattern", crate::AssistKind::RefactorRewrite),
+        "Fill struct fields",
+        target_range,
+        move |builder| builder.replace_ast(old_field_list, new_field_list),
+    )
+}
+// Assist: expand_tuple_struct_rest_pattern
+//
+// Fills fields by replacing rest pattern in tuple struct patterns.
+//
+// ```
+// struct Bar(Y, Z);
+//
+// fn foo(bar: Bar) {
+//     let Bar(..$0) = bar;
+// }
+// ```
+// ->
+// ```
+// struct Bar(Y, Z);
+//
+// fn foo(bar: Bar) {
+//     let Bar(_0, _1) = bar;
+// }
+// ```
+fn expand_tuple_struct_rest_pattern(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+    pat: ast::TupleStructPat,
+    rest_pat: ast::RestPat,
+) -> Option<()> {
+    let path = pat.path()?;
+    let fields = match ctx.sema.type_of_pat(&pat.clone().into())?.original.as_adt()? {
+        hir::Adt::Struct(s) if s.kind(ctx.sema.db) == StructKind::Tuple => s.fields(ctx.sema.db),
+        hir::Adt::Enum(_) => match ctx.sema.resolve_path(&path)? {
+            PathResolution::Def(hir::ModuleDef::Variant(v))
+                if v.kind(ctx.sema.db) == StructKind::Tuple =>
+            {
+                v.fields(ctx.sema.db)
+            }
+            _ => return None,
+        },
+        _ => return None,
+    };
+
+    let rest_pat = rest_pat.into();
+    let mut pats = pat.fields();
+    let prefix_count = pats.by_ref().position(|p| p == rest_pat)?;
+    let suffix_count = pats.count();
+
+    if fields.len().saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
+        cov_mark::hit!(no_missing_fields_tuple_struct);
+        return None;
+    }
+
+    let old_range = ctx.sema.original_range_opt(pat.syntax())?;
     if old_range.file_id != ctx.file_id() {
         return None;
     }
 
+    let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax()));
+    let new_pat = make::tuple_struct_pat(
+        path,
+        pat.fields()
+            .take(prefix_count)
+            .chain(fields[prefix_count..fields.len() - suffix_count].iter().map(|f| {
+                make::ident_pat(
+                    false,
+                    false,
+                    match name_gen.for_type(&f.ty(ctx.sema.db), ctx.sema.db, ctx.edition()) {
+                        Some(name) => make::name(&name),
+                        None => make::name(&format!("_{}", f.index())),
+                    },
+                )
+                .into()
+            }))
+            .chain(pat.fields().skip(prefix_count + 1)),
+    );
+
+    let target_range = rest_pat.syntax().text_range();
     acc.add(
-        AssistId("fill_record_pattern_fields", crate::AssistKind::RefactorRewrite),
-        "Fill structure fields",
+        AssistId("expand_tuple_struct_rest_pattern", crate::AssistKind::RefactorRewrite),
+        "Fill tuple struct fields",
         target_range,
-        move |builder| builder.replace_ast(old_field_list, new_field_list),
+        move |builder| builder.replace_ast(pat, new_pat),
     )
 }
 
@@ -73,7 +169,7 @@ mod tests {
     #[test]
     fn fill_fields_enum_with_only_ellipsis() {
         check_assist(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 enum Foo {
     A(X),
@@ -106,7 +202,7 @@ fn bar(foo: Foo) {
     #[test]
     fn fill_fields_enum_with_fields() {
         check_assist(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 enum Foo {
     A(X),
@@ -139,7 +235,7 @@ fn bar(foo: Foo) {
     #[test]
     fn fill_fields_struct_with_only_ellipsis() {
         check_assist(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 struct Bar {
     y: Y,
@@ -160,13 +256,34 @@ fn foo(bar: Bar) {
     let Bar { y, z  } = bar;
 }
 "#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+struct Y;
+struct Z;
+struct Bar(Y, Z)
+
+fn foo(bar: Bar) {
+    let Bar(..$0) = bar;
+}
+"#,
+            r#"
+struct Y;
+struct Z;
+struct Bar(Y, Z)
+
+fn foo(bar: Bar) {
+    let Bar(y, z) = bar;
+}
+"#,
         )
     }
 
     #[test]
     fn fill_fields_struct_with_fields() {
         check_assist(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 struct Bar {
     y: Y,
@@ -187,13 +304,36 @@ fn foo(bar: Bar) {
     let Bar { y, z } = bar;
 }
 "#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+struct X;
+struct Y;
+struct Z;
+struct Bar(X, Y, Z)
+
+fn foo(bar: Bar) {
+    let Bar(x, ..$0, z) = bar;
+}
+"#,
+            r#"
+struct X;
+struct Y;
+struct Z;
+struct Bar(X, Y, Z)
+
+fn foo(bar: Bar) {
+    let Bar(x, y, z) = bar;
+}
+"#,
         )
     }
 
     #[test]
     fn fill_fields_struct_generated_by_macro() {
         check_assist(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 macro_rules! position {
     ($t: ty) => {
@@ -226,7 +366,7 @@ fn macro_call(pos: Pos) {
     #[test]
     fn fill_fields_enum_generated_by_macro() {
         check_assist(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 macro_rules! enum_gen {
     ($t: ty) => {
@@ -271,7 +411,7 @@ fn macro_call(foo: Foo) {
     #[test]
     fn not_applicable_when_not_in_ellipsis() {
         check_assist_not_applicable(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 enum Foo {
     A(X),
@@ -287,7 +427,7 @@ fn bar(foo: Foo) {
 "#,
         );
         check_assist_not_applicable(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 enum Foo {
     A(X),
@@ -303,7 +443,7 @@ fn bar(foo: Foo) {
 "#,
         );
         check_assist_not_applicable(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 enum Foo {
     A(X),
@@ -324,8 +464,9 @@ fn bar(foo: Foo) {
     fn not_applicable_when_no_missing_fields() {
         // This is still possible even though it's meaningless
         cov_mark::check!(no_missing_fields);
+        cov_mark::check!(no_missing_fields_tuple_struct);
         check_assist_not_applicable(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 enum Foo {
     A(X),
@@ -341,7 +482,7 @@ fn bar(foo: Foo) {
 "#,
         );
         check_assist_not_applicable(
-            fill_record_pattern_fields,
+            expand_rest_pattern,
             r#"
 struct Bar {
     y: Y,
@@ -353,5 +494,15 @@ fn foo(bar: Bar) {
 }
 "#,
         );
+        check_assist_not_applicable(
+            expand_rest_pattern,
+            r#"
+struct Bar(Y, Z)
+
+fn foo(bar: Bar) {
+    let Bar(y, ..$0, z) = bar;
+}
+"#,
+        );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 751e4a5a571..330587e0dbf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -750,7 +750,10 @@ impl FunctionBody {
                         ast::Stmt::Item(_) => (),
                         ast::Stmt::LetStmt(stmt) => {
                             if let Some(pat) = stmt.pat() {
-                                walk_pat(&pat, cb);
+                                walk_pat(&pat, &mut |pat| {
+                                    cb(pat);
+                                    std::ops::ControlFlow::<(), ()>::Continue(())
+                                });
                             }
                             if let Some(expr) = stmt.initializer() {
                                 walk_patterns_in_expr(&expr, cb);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 91e248a1de5..7af2a2e1e6a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -724,9 +724,9 @@ fn fn_generic_params(
     filter_unnecessary_bounds(&mut generic_params, &mut where_preds, necessary_params);
     filter_bounds_in_scope(&mut generic_params, &mut where_preds, ctx, target);
 
-    let generic_params: Vec<_> =
+    let generic_params: Vec<ast::GenericParam> =
         generic_params.into_iter().map(|it| it.node.clone_for_update()).collect();
-    let where_preds: Vec<_> =
+    let where_preds: Vec<ast::WherePred> =
         where_preds.into_iter().map(|it| it.node.clone_for_update()).collect();
 
     // 4. Rewrite paths
@@ -1116,9 +1116,12 @@ fn fn_arg_type(
 
         if ty.is_reference() || ty.is_mutable_reference() {
             let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
-            let target_edition = target_module.krate().edition(ctx.db());
             convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
-                .map(|conversion| conversion.convert_type(ctx.db(), target_edition).to_string())
+                .map(|conversion| {
+                    conversion
+                        .convert_type(ctx.db(), target_module.krate().to_display_target(ctx.db()))
+                        .to_string()
+                })
                 .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
         } else {
             ty.display_source_code(ctx.db(), target_module.into(), true).ok()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index ac58af62525..1b16ba5fc8f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -233,7 +233,7 @@ fn generate_getter_from_info(
                 .map(|conversion| {
                     cov_mark::hit!(convert_reference_type);
                     (
-                        conversion.convert_type(ctx.db(), krate.edition(ctx.db())),
+                        conversion.convert_type(ctx.db(), krate.to_display_target(ctx.db())),
                         conversion.getter(record_field_info.field_name.to_string()),
                     )
                 })
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index 139078eee7c..ca5882d0313 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -42,7 +42,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
         let value = konst
             .eval(ctx.sema.db)
             .ok()?
-            .render(ctx.sema.db, konst.krate(ctx.sema.db).edition(ctx.sema.db));
+            .render(ctx.sema.db, konst.krate(ctx.sema.db).to_display_target(ctx.sema.db));
 
         let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
index cc7bea5152b..36eed290dc8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
@@ -5,7 +5,7 @@ use ide_db::{
     EditionedFileId, RootDatabase,
 };
 use syntax::{
-    ast::{self, AstNode, AstToken, HasName},
+    ast::{self, syntax_factory::SyntaxFactory, AstNode, AstToken, HasName},
     SyntaxElement, TextRange,
 };
 
@@ -43,22 +43,6 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
         }?;
     let initializer_expr = let_stmt.initializer()?;
 
-    let delete_range = delete_let.then(|| {
-        if let Some(whitespace) = let_stmt
-            .syntax()
-            .next_sibling_or_token()
-            .and_then(SyntaxElement::into_token)
-            .and_then(ast::Whitespace::cast)
-        {
-            TextRange::new(
-                let_stmt.syntax().text_range().start(),
-                whitespace.syntax().text_range().end(),
-            )
-        } else {
-            let_stmt.syntax().text_range()
-        }
-    });
-
     let wrap_in_parens = references
         .into_iter()
         .filter_map(|FileReference { range, name, .. }| match name {
@@ -73,40 +57,60 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
             }
             let usage_node =
                 name_ref.syntax().ancestors().find(|it| ast::PathExpr::can_cast(it.kind()));
-            let usage_parent_option = usage_node.and_then(|it| it.parent());
+            let usage_parent_option = usage_node.as_ref().and_then(|it| it.parent());
             let usage_parent = match usage_parent_option {
                 Some(u) => u,
-                None => return Some((range, name_ref, false)),
+                None => return Some((name_ref, false)),
             };
-            Some((range, name_ref, initializer_expr.needs_parens_in(&usage_parent)))
+            let should_wrap = initializer_expr
+                .needs_parens_in_place_of(&usage_parent, usage_node.as_ref().unwrap());
+            Some((name_ref, should_wrap))
         })
         .collect::<Option<Vec<_>>>()?;
 
-    let init_str = initializer_expr.syntax().text().to_string();
-    let init_in_paren = format!("({init_str})");
-
     let target = match target {
-        ast::NameOrNameRef::Name(it) => it.syntax().text_range(),
-        ast::NameOrNameRef::NameRef(it) => it.syntax().text_range(),
+        ast::NameOrNameRef::Name(it) => it.syntax().clone(),
+        ast::NameOrNameRef::NameRef(it) => it.syntax().clone(),
     };
 
     acc.add(
         AssistId("inline_local_variable", AssistKind::RefactorInline),
         "Inline variable",
-        target,
+        target.text_range(),
         move |builder| {
-            if let Some(range) = delete_range {
-                builder.delete(range);
+            let mut editor = builder.make_editor(&target);
+            if delete_let {
+                editor.delete(let_stmt.syntax());
+                if let Some(whitespace) = let_stmt
+                    .syntax()
+                    .next_sibling_or_token()
+                    .and_then(SyntaxElement::into_token)
+                    .and_then(ast::Whitespace::cast)
+                {
+                    editor.delete(whitespace.syntax());
+                }
             }
-            for (range, name, should_wrap) in wrap_in_parens {
-                let replacement = if should_wrap { &init_in_paren } else { &init_str };
-                if ast::RecordExprField::for_field_name(&name).is_some() {
+
+            let make = SyntaxFactory::new();
+
+            for (name, should_wrap) in wrap_in_parens {
+                let replacement = if should_wrap {
+                    make.expr_paren(initializer_expr.clone()).into()
+                } else {
+                    initializer_expr.clone()
+                };
+
+                if let Some(record_field) = ast::RecordExprField::for_field_name(&name) {
                     cov_mark::hit!(inline_field_shorthand);
-                    builder.insert(range.end(), format!(": {replacement}"));
+                    let replacement = make.record_expr_field(name, Some(replacement));
+                    editor.replace(record_field.syntax(), replacement.syntax());
                 } else {
-                    builder.replace(range, replacement.clone())
+                    editor.replace(name.syntax(), replacement.syntax());
                 }
             }
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
@@ -942,4 +946,52 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn test_wrap_in_parens() {
+        check_assist(
+            inline_local_variable,
+            r#"
+fn main() {
+    let $0a = 123 < 456;
+    let b = !a;
+}
+"#,
+            r#"
+fn main() {
+    let b = !(123 < 456);
+}
+"#,
+        );
+        check_assist(
+            inline_local_variable,
+            r#"
+trait Foo {
+    fn foo(&self);
+}
+
+impl Foo for bool {
+    fn foo(&self) {}
+}
+
+fn main() {
+    let $0a = 123 < 456;
+    let b = a.foo();
+}
+"#,
+            r#"
+trait Foo {
+    fn foo(&self);
+}
+
+impl Foo for bool {
+    fn foo(&self) {}
+}
+
+fn main() {
+    let b = (123 < 456).foo();
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs
index 8c276415bb1..994e4a0edda 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs
@@ -4,7 +4,7 @@ use syntax::ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
-// Assist: introduce_named_generic
+// Assist: introduce_named_type_parameter
 //
 // Replaces `impl Trait` function argument with the named generic.
 //
@@ -15,18 +15,20 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 // ```
 // fn foo<$0B: Bar>(bar: B) {}
 // ```
-pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+pub(crate) fn introduce_named_type_parameter(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
     let impl_trait_type = ctx.find_node_at_offset::<ast::ImplTraitType>()?;
     let param = impl_trait_type.syntax().ancestors().find_map(ast::Param::cast)?;
-    let fn_ = param.syntax().ancestors().find_map(ast::Fn::cast)?;
-
+    let fn_ = param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?;
     let type_bound_list = impl_trait_type.type_bound_list()?;
 
     let make = SyntaxFactory::new();
     let target = fn_.syntax().text_range();
     acc.add(
-        AssistId("introduce_named_generic", AssistKind::RefactorRewrite),
-        "Replace impl trait with generic",
+        AssistId("introduce_named_type_parameter", AssistKind::RefactorRewrite),
+        "Replace impl trait with type parameter",
         target,
         |builder| {
             let mut editor = builder.make_editor(fn_.syntax());
@@ -71,7 +73,7 @@ mod tests {
     #[test]
     fn introduce_named_generic_params() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo<G>(bar: $0impl Bar) {}"#,
             r#"fn foo<G, $0B: Bar>(bar: B) {}"#,
         );
@@ -80,7 +82,7 @@ mod tests {
     #[test]
     fn replace_impl_trait_without_generic_params() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo(bar: $0impl Bar) {}"#,
             r#"fn foo<$0B: Bar>(bar: B) {}"#,
         );
@@ -89,7 +91,7 @@ mod tests {
     #[test]
     fn replace_two_impl_trait_with_generic_params() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo<G>(foo: impl Foo, bar: $0impl Bar) {}"#,
             r#"fn foo<G, $0B: Bar>(foo: impl Foo, bar: B) {}"#,
         );
@@ -98,7 +100,7 @@ mod tests {
     #[test]
     fn replace_impl_trait_with_empty_generic_params() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo<>(bar: $0impl Bar) {}"#,
             r#"fn foo<$0B: Bar>(bar: B) {}"#,
         );
@@ -107,7 +109,7 @@ mod tests {
     #[test]
     fn replace_impl_trait_with_empty_multiline_generic_params() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"
 fn foo<
 >(bar: $0impl Bar) {}
@@ -122,7 +124,7 @@ fn foo<$0B: Bar
     #[test]
     fn replace_impl_trait_with_exist_generic_letter() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo<B>(bar: $0impl Bar) {}"#,
             r#"fn foo<B, $0B1: Bar>(bar: B1) {}"#,
         );
@@ -131,7 +133,7 @@ fn foo<$0B: Bar
     #[test]
     fn replace_impl_trait_with_more_exist_generic_letter() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo<B, B0, B1, B3>(bar: $0impl Bar) {}"#,
             r#"fn foo<B, B0, B1, B3, $0B4: Bar>(bar: B4) {}"#,
         );
@@ -140,7 +142,7 @@ fn foo<$0B: Bar
     #[test]
     fn replace_impl_trait_with_multiline_generic_params() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"
 fn foo<
     G: Foo,
@@ -161,7 +163,7 @@ fn foo<
     #[test]
     fn replace_impl_trait_multiple() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn foo(bar: $0impl Foo + Bar) {}"#,
             r#"fn foo<$0F: Foo + Bar>(bar: F) {}"#,
         );
@@ -170,7 +172,7 @@ fn foo<
     #[test]
     fn replace_impl_with_mut() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn f(iter: &mut $0impl Iterator<Item = i32>) {}"#,
             r#"fn f<$0I: Iterator<Item = i32>>(iter: &mut I) {}"#,
         );
@@ -179,7 +181,7 @@ fn foo<
     #[test]
     fn replace_impl_inside() {
         check_assist(
-            introduce_named_generic,
+            introduce_named_type_parameter,
             r#"fn f(x: &mut Vec<$0impl Iterator<Item = i32>>) {}"#,
             r#"fn f<$0I: Iterator<Item = i32>>(x: &mut Vec<I>) {}"#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 66671c934c4..e10897b3bef 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -52,8 +52,13 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     let paths = paths
         .into_iter()
         .filter_map(|path| {
-            path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config(), edition)
-                .ok()
+            path.gen_source_code(
+                &scope,
+                &mut formatter,
+                ctx.config.import_path_config(),
+                scope.krate().to_display_target(ctx.db()),
+            )
+            .ok()
         })
         .unique();
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 448bcadb8ef..e8480b0de19 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -105,6 +105,7 @@ mod handlers {
     pub(crate) type Handler = fn(&mut Assists, &AssistContext<'_>) -> Option<()>;
 
     mod add_braces;
+    mod add_explicit_enum_discriminant;
     mod add_explicit_type;
     mod add_label_to_loop;
     mod add_lifetime_to_type;
@@ -115,9 +116,9 @@ mod handlers {
     mod apply_demorgan;
     mod auto_import;
     mod bind_unused_param;
-    mod bool_to_enum;
     mod change_visibility;
     mod convert_bool_then;
+    mod convert_bool_to_enum;
     mod convert_closure_to_fn;
     mod convert_comment_block;
     mod convert_comment_from_or_to_doc;
@@ -138,14 +139,13 @@ mod handlers {
     mod destructure_tuple_binding;
     mod desugar_doc_comment;
     mod expand_glob_import;
-    mod explicit_enum_discriminant;
+    mod expand_rest_pattern;
     mod extract_expressions_from_format_string;
     mod extract_function;
     mod extract_module;
     mod extract_struct_from_enum_variant;
     mod extract_type_alias;
     mod extract_variable;
-    mod fill_record_pattern_fields;
     mod fix_visibility;
     mod flip_binexpr;
     mod flip_comma;
@@ -177,8 +177,8 @@ mod handlers {
     mod inline_macro;
     mod inline_type_alias;
     mod into_to_qualified_from;
-    mod introduce_named_generic;
     mod introduce_named_lifetime;
+    mod introduce_named_type_parameter;
     mod invert_if;
     mod merge_imports;
     mod merge_match_arms;
@@ -234,49 +234,47 @@ mod handlers {
         &[
             // These are alphabetic for the foolish consistency
             add_braces::add_braces,
+            add_explicit_enum_discriminant::add_explicit_enum_discriminant,
             add_explicit_type::add_explicit_type,
             add_label_to_loop::add_label_to_loop,
-            add_missing_match_arms::add_missing_match_arms,
             add_lifetime_to_type::add_lifetime_to_type,
+            add_missing_match_arms::add_missing_match_arms,
             add_return_type::add_return_type,
             add_turbo_fish::add_turbo_fish,
-            apply_demorgan::apply_demorgan,
             apply_demorgan::apply_demorgan_iterator,
+            apply_demorgan::apply_demorgan,
             auto_import::auto_import,
             bind_unused_param::bind_unused_param,
-            bool_to_enum::bool_to_enum,
             change_visibility::change_visibility,
             convert_bool_then::convert_bool_then_to_if,
             convert_bool_then::convert_if_to_bool_then,
-            toggle_async_sugar::desugar_async_into_impl_future,
-            toggle_async_sugar::sugar_impl_future_into_async,
+            convert_bool_to_enum::convert_bool_to_enum,
+            convert_closure_to_fn::convert_closure_to_fn,
             convert_comment_block::convert_comment_block,
             convert_comment_from_or_to_doc::convert_comment_from_or_to_doc,
-            convert_closure_to_fn::convert_closure_to_fn,
             convert_from_to_tryfrom::convert_from_to_tryfrom,
             convert_integer_literal::convert_integer_literal,
             convert_into_to_from::convert_into_to_from,
-            convert_iter_for_each_to_for::convert_iter_for_each_to_for,
             convert_iter_for_each_to_for::convert_for_loop_with_for_each,
+            convert_iter_for_each_to_for::convert_iter_for_each_to_for,
             convert_let_else_to_match::convert_let_else_to_match,
             convert_match_to_let_else::convert_match_to_let_else,
-            convert_tuple_return_type_to_struct::convert_tuple_return_type_to_struct,
             convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
             convert_nested_function_to_closure::convert_nested_function_to_closure,
             convert_to_guarded_return::convert_to_guarded_return,
+            convert_tuple_return_type_to_struct::convert_tuple_return_type_to_struct,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
             convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
             convert_while_to_loop::convert_while_to_loop,
-            desugar_doc_comment::desugar_doc_comment,
-            destructure_tuple_binding::destructure_tuple_binding,
             destructure_struct_binding::destructure_struct_binding,
+            destructure_tuple_binding::destructure_tuple_binding,
+            desugar_doc_comment::desugar_doc_comment,
             expand_glob_import::expand_glob_import,
             expand_glob_import::expand_glob_reexport,
-            explicit_enum_discriminant::explicit_enum_discriminant,
+            expand_rest_pattern::expand_rest_pattern,
             extract_expressions_from_format_string::extract_expressions_from_format_string,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
             extract_type_alias::extract_type_alias,
-            fill_record_pattern_fields::fill_record_pattern_fields,
             fix_visibility::fix_visibility,
             flip_binexpr::flip_binexpr,
             flip_comma::flip_comma,
@@ -287,8 +285,8 @@ mod handlers {
             generate_default_from_new::generate_default_from_new,
             generate_delegate_trait::generate_delegate_trait,
             generate_derive::generate_derive,
-            generate_documentation_template::generate_documentation_template,
             generate_documentation_template::generate_doc_example,
+            generate_documentation_template::generate_documentation_template,
             generate_enum_is_method::generate_enum_is_method,
             generate_enum_projection_method::generate_enum_as_method,
             generate_enum_projection_method::generate_enum_try_into_method,
@@ -298,8 +296,8 @@ mod handlers {
             generate_function::generate_function,
             generate_impl::generate_impl,
             generate_impl::generate_trait_impl,
-            generate_mut_trait_impl::generate_mut_trait_impl,
             generate_is_empty_from_len::generate_is_empty_from_len,
+            generate_mut_trait_impl::generate_mut_trait_impl,
             generate_new::generate_new,
             generate_trait_from_impl::generate_trait_from_impl,
             inline_call::inline_call,
@@ -307,39 +305,41 @@ mod handlers {
             inline_const_as_literal::inline_const_as_literal,
             inline_local_variable::inline_local_variable,
             inline_macro::inline_macro,
-            inline_type_alias::inline_type_alias,
             inline_type_alias::inline_type_alias_uses,
+            inline_type_alias::inline_type_alias,
             into_to_qualified_from::into_to_qualified_from,
-            introduce_named_generic::introduce_named_generic,
             introduce_named_lifetime::introduce_named_lifetime,
+            introduce_named_type_parameter::introduce_named_type_parameter,
             invert_if::invert_if,
             merge_imports::merge_imports,
             merge_match_arms::merge_match_arms,
             merge_nested_if::merge_nested_if,
             move_bounds::move_bounds_to_where_clause,
             move_const_to_impl::move_const_to_impl,
+            move_from_mod_rs::move_from_mod_rs,
             move_guard::move_arm_cond_to_match_guard,
             move_guard::move_guard_to_arm_body,
             move_module_to_file::move_module_to_file,
             move_to_mod_rs::move_to_mod_rs,
-            move_from_mod_rs::move_from_mod_rs,
             normalize_import::normalize_import,
             number_representation::reformat_number_literal,
-            pull_assignment_up::pull_assignment_up,
             promote_local_to_const::promote_local_to_const,
-            qualify_path::qualify_path,
+            pull_assignment_up::pull_assignment_up,
             qualify_method_call::qualify_method_call,
+            qualify_path::qualify_path,
             raw_string::add_hash,
             raw_string::make_usual_string,
             raw_string::remove_hash,
             remove_dbg::remove_dbg,
             remove_mut::remove_mut,
+            remove_parentheses::remove_parentheses,
             remove_unused_imports::remove_unused_imports,
             remove_unused_param::remove_unused_param,
-            remove_parentheses::remove_parentheses,
             reorder_fields::reorder_fields,
             reorder_impl_items::reorder_impl_items,
-            replace_try_expr_with_match::replace_try_expr_with_match,
+            replace_arith_op::replace_arith_with_checked,
+            replace_arith_op::replace_arith_with_saturating,
+            replace_arith_op::replace_arith_with_wrapping,
             replace_derive_with_manual_impl::replace_derive_with_manual_impl,
             replace_if_let_with_match::replace_if_let_with_match,
             replace_if_let_with_match::replace_match_with_if_let,
@@ -348,23 +348,23 @@ mod handlers {
             replace_method_eager_lazy::replace_with_eager_method,
             replace_method_eager_lazy::replace_with_lazy_method,
             replace_named_generic_with_impl::replace_named_generic_with_impl,
-            replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
             replace_qualified_name_with_use::replace_qualified_name_with_use,
-            replace_arith_op::replace_arith_with_wrapping,
-            replace_arith_op::replace_arith_with_checked,
-            replace_arith_op::replace_arith_with_saturating,
+            replace_try_expr_with_match::replace_try_expr_with_match,
+            replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
             sort_items::sort_items,
             split_import::split_import,
             term_search::term_search,
+            toggle_async_sugar::desugar_async_into_impl_future,
+            toggle_async_sugar::sugar_impl_future_into_async,
             toggle_ignore::toggle_ignore,
             toggle_macro_delimiter::toggle_macro_delimiter,
             unmerge_match_arm::unmerge_match_arm,
             unmerge_use::unmerge_use,
             unnecessary_async::unnecessary_async,
+            unqualify_method_call::unqualify_method_call,
             unwrap_block::unwrap_block,
             unwrap_return_type::unwrap_return_type,
             unwrap_tuple::unwrap_tuple,
-            unqualify_method_call::unqualify_method_call,
             wrap_return_type::wrap_return_type,
             wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr,
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index 11aeb21c77e..7d7012c4622 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -710,18 +710,22 @@ pub fn test_some_range(a: int) -> bool {
                                         Indel {
                                             insert: "let",
                                             delete: 45..47,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "var_name",
                                             delete: 48..60,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "=",
                                             delete: 61..81,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "5;\n    if let 2..6 = var_name {\n        true\n    } else {\n        false\n    }",
                                             delete: 82..108,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -739,6 +743,8 @@ pub fn test_some_range(a: int) -> bool {
                         },
                         file_system_edits: [],
                         is_snippet: true,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: Some(
@@ -839,18 +845,22 @@ pub fn test_some_range(a: int) -> bool {
                                         Indel {
                                             insert: "let",
                                             delete: 45..47,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "var_name",
                                             delete: 48..60,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "=",
                                             delete: 61..81,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "5;\n    if let 2..6 = var_name {\n        true\n    } else {\n        false\n    }",
                                             delete: 82..108,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -868,6 +878,8 @@ pub fn test_some_range(a: int) -> bool {
                         },
                         file_system_edits: [],
                         is_snippet: true,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: Some(
@@ -902,22 +914,27 @@ pub fn test_some_range(a: int) -> bool {
                                         Indel {
                                             insert: "const",
                                             delete: 45..47,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "VAR_NAME:",
                                             delete: 48..60,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "i32",
                                             delete: 61..81,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "=",
                                             delete: 82..86,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "5;\n    if let 2..6 = VAR_NAME {\n        true\n    } else {\n        false\n    }",
                                             delete: 87..108,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -935,6 +952,8 @@ pub fn test_some_range(a: int) -> bool {
                         },
                         file_system_edits: [],
                         is_snippet: true,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: Some(
@@ -969,22 +988,27 @@ pub fn test_some_range(a: int) -> bool {
                                         Indel {
                                             insert: "static",
                                             delete: 45..47,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "VAR_NAME:",
                                             delete: 48..60,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "i32",
                                             delete: 61..81,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "=",
                                             delete: 82..86,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "5;\n    if let 2..6 = VAR_NAME {\n        true\n    } else {\n        false\n    }",
                                             delete: 87..108,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -1002,6 +1026,8 @@ pub fn test_some_range(a: int) -> bool {
                         },
                         file_system_edits: [],
                         is_snippet: true,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: Some(
@@ -1036,10 +1062,12 @@ pub fn test_some_range(a: int) -> bool {
                                         Indel {
                                             insert: "fun_name()",
                                             delete: 59..60,
+                                            annotation: None,
                                         },
                                         Indel {
                                             insert: "\n\nfn fun_name() -> i32 {\n    5\n}",
                                             delete: 110..110,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -1057,6 +1085,8 @@ pub fn test_some_range(a: int) -> bool {
                         },
                         file_system_edits: [],
                         is_snippet: true,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: None,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 91c1a3e1bd7..4234124d670 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -28,6 +28,29 @@ fn foo(n: i32) -> i32 {
 }
 
 #[test]
+fn doctest_add_explicit_enum_discriminant() {
+    check_doc_test(
+        "add_explicit_enum_discriminant",
+        r#####"
+enum TheEnum$0 {
+    Foo,
+    Bar,
+    Baz = 42,
+    Quux,
+}
+"#####,
+        r#####"
+enum TheEnum {
+    Foo = 0,
+    Bar = 1,
+    Baz = 42,
+    Quux = 43,
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_add_explicit_type() {
     check_doc_test(
         "add_explicit_type",
@@ -305,34 +328,6 @@ fn some_function(x: i32) {
 }
 
 #[test]
-fn doctest_bool_to_enum() {
-    check_doc_test(
-        "bool_to_enum",
-        r#####"
-fn main() {
-    let $0bool = true;
-
-    if bool {
-        println!("foo");
-    }
-}
-"#####,
-        r#####"
-#[derive(PartialEq, Eq)]
-enum Bool { True, False }
-
-fn main() {
-    let bool = Bool::True;
-
-    if bool == Bool::True {
-        println!("foo");
-    }
-}
-"#####,
-    )
-}
-
-#[test]
 fn doctest_change_visibility() {
     check_doc_test(
         "change_visibility",
@@ -383,6 +378,34 @@ fn main() {
 }
 
 #[test]
+fn doctest_convert_bool_to_enum() {
+    check_doc_test(
+        "convert_bool_to_enum",
+        r#####"
+fn main() {
+    let $0bool = true;
+
+    if bool {
+        println!("foo");
+    }
+}
+"#####,
+        r#####"
+#[derive(PartialEq, Eq)]
+enum Bool { True, False }
+
+fn main() {
+    let bool = Bool::True;
+
+    if bool == Bool::True {
+        println!("foo");
+    }
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_convert_closure_to_fn() {
     check_doc_test(
         "convert_closure_to_fn",
@@ -933,23 +956,42 @@ pub use foo::{Bar, Baz};
 }
 
 #[test]
-fn doctest_explicit_enum_discriminant() {
+fn doctest_expand_record_rest_pattern() {
     check_doc_test(
-        "explicit_enum_discriminant",
+        "expand_record_rest_pattern",
         r#####"
-enum TheEnum$0 {
-    Foo,
-    Bar,
-    Baz = 42,
-    Quux,
+struct Bar { y: Y, z: Z }
+
+fn foo(bar: Bar) {
+    let Bar { ..$0 } = bar;
 }
 "#####,
         r#####"
-enum TheEnum {
-    Foo = 0,
-    Bar = 1,
-    Baz = 42,
-    Quux = 43,
+struct Bar { y: Y, z: Z }
+
+fn foo(bar: Bar) {
+    let Bar { y, z  } = bar;
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_expand_tuple_struct_rest_pattern() {
+    check_doc_test(
+        "expand_tuple_struct_rest_pattern",
+        r#####"
+struct Bar(Y, Z);
+
+fn foo(bar: Bar) {
+    let Bar(..$0) = bar;
+}
+"#####,
+        r#####"
+struct Bar(Y, Z);
+
+fn foo(bar: Bar) {
+    let Bar(_0, _1) = bar;
 }
 "#####,
     )
@@ -1118,27 +1160,6 @@ fn main() {
 }
 
 #[test]
-fn doctest_fill_record_pattern_fields() {
-    check_doc_test(
-        "fill_record_pattern_fields",
-        r#####"
-struct Bar { y: Y, z: Z }
-
-fn foo(bar: Bar) {
-    let Bar { ..$0 } = bar;
-}
-"#####,
-        r#####"
-struct Bar { y: Y, z: Z }
-
-fn foo(bar: Bar) {
-    let Bar { y, z  } = bar;
-}
-"#####,
-    )
-}
-
-#[test]
 fn doctest_fix_visibility() {
     check_doc_test(
         "fix_visibility",
@@ -2194,19 +2215,6 @@ fn main() -> () {
 }
 
 #[test]
-fn doctest_introduce_named_generic() {
-    check_doc_test(
-        "introduce_named_generic",
-        r#####"
-fn foo(bar: $0impl Bar) {}
-"#####,
-        r#####"
-fn foo<$0B: Bar>(bar: B) {}
-"#####,
-    )
-}
-
-#[test]
 fn doctest_introduce_named_lifetime() {
     check_doc_test(
         "introduce_named_lifetime",
@@ -2232,6 +2240,19 @@ impl<'a> Cursor<'a> {
 }
 
 #[test]
+fn doctest_introduce_named_type_parameter() {
+    check_doc_test(
+        "introduce_named_type_parameter",
+        r#####"
+fn foo(bar: $0impl Bar) {}
+"#####,
+        r#####"
+fn foo<$0B: Bar>(bar: B) {}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_invert_if() {
     check_doc_test(
         "invert_if",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 39686f065a9..a6fa1706710 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -3,7 +3,8 @@
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 use hir::{
     db::{ExpandDatabase, HirDatabase},
-    HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, Semantics,
+    DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution,
+    Semantics,
 };
 use ide_db::{
     famous_defs::FamousDefs,
@@ -21,7 +22,7 @@ use syntax::{
         syntax_factory::SyntaxFactory,
         HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
-    ted, AstNode, AstToken, Direction, Edition, NodeOrToken, SourceFile,
+    ted, AstNode, AstToken, Direction, NodeOrToken, SourceFile,
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, TextRange, TextSize, WalkEvent, T,
 };
@@ -793,31 +794,50 @@ enum ReferenceConversionType {
 }
 
 impl ReferenceConversion {
-    pub(crate) fn convert_type(&self, db: &dyn HirDatabase, edition: Edition) -> ast::Type {
+    pub(crate) fn convert_type(
+        &self,
+        db: &dyn HirDatabase,
+        display_target: DisplayTarget,
+    ) -> ast::Type {
         let ty = match self.conversion {
-            ReferenceConversionType::Copy => self.ty.display(db, edition).to_string(),
+            ReferenceConversionType::Copy => self.ty.display(db, display_target).to_string(),
             ReferenceConversionType::AsRefStr => "&str".to_owned(),
             ReferenceConversionType::AsRefSlice => {
-                let type_argument_name =
-                    self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
+                let type_argument_name = self
+                    .ty
+                    .type_arguments()
+                    .next()
+                    .unwrap()
+                    .display(db, display_target)
+                    .to_string();
                 format!("&[{type_argument_name}]")
             }
             ReferenceConversionType::Dereferenced => {
-                let type_argument_name =
-                    self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
+                let type_argument_name = self
+                    .ty
+                    .type_arguments()
+                    .next()
+                    .unwrap()
+                    .display(db, display_target)
+                    .to_string();
                 format!("&{type_argument_name}")
             }
             ReferenceConversionType::Option => {
-                let type_argument_name =
-                    self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
+                let type_argument_name = self
+                    .ty
+                    .type_arguments()
+                    .next()
+                    .unwrap()
+                    .display(db, display_target)
+                    .to_string();
                 format!("Option<&{type_argument_name}>")
             }
             ReferenceConversionType::Result => {
                 let mut type_arguments = self.ty.type_arguments();
                 let first_type_argument_name =
-                    type_arguments.next().unwrap().display(db, edition).to_string();
+                    type_arguments.next().unwrap().display(db, display_target).to_string();
                 let second_type_argument_name =
-                    type_arguments.next().unwrap().display(db, edition).to_string();
+                    type_arguments.next().unwrap().display(db, display_target).to_string();
                 format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>")
             }
         };
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index 365d2dde7e9..b28b6e50e22 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -365,7 +365,8 @@ pub(crate) fn complete_expr_path(
                     add_keyword("false", "false");
 
                     if in_condition || in_block_expr {
-                        add_keyword("let", "let");
+                        add_keyword("letm", "let mut $0");
+                        add_keyword("let", "let $0");
                     }
 
                     if after_if_expr {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
index 6541ee502d8..26c29e0202c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
@@ -330,4 +330,34 @@ fn main() {
 ",
         )
     }
+
+    #[test]
+    fn completes_let_with_space() {
+        check_edit(
+            "let",
+            r#"
+fn main() {
+    $0
+}
+"#,
+            r#"
+fn main() {
+    let $0
+}
+"#,
+        );
+        check_edit(
+            "letm",
+            r#"
+fn main() {
+    $0
+}
+"#,
+            r#"
+fn main() {
+    let mut $0
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 919b30f7f97..e686a293094 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -7,8 +7,8 @@ mod tests;
 use std::{iter, ops::ControlFlow};
 
 use hir::{
-    HasAttrs, Local, ModPath, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef, Semantics,
-    SemanticsScope, Symbol, Type, TypeInfo,
+    DisplayTarget, HasAttrs, Local, ModPath, ModuleDef, ModuleSource, Name, PathResolution,
+    ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
 };
 use ide_db::{
     base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition,
@@ -440,6 +440,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(crate) token: SyntaxToken,
     /// The crate of the current file.
     pub(crate) krate: hir::Crate,
+    pub(crate) display_target: DisplayTarget,
     /// The module of the `scope`.
     pub(crate) module: hir::Module,
     /// The function where we're completing, if inside a function.
@@ -867,6 +868,7 @@ impl<'a> CompletionContext<'a> {
             CompleteSemicolon::DoNotComplete
         };
 
+        let display_target = krate.to_display_target(db);
         let ctx = CompletionContext {
             sema,
             scope,
@@ -888,6 +890,7 @@ impl<'a> CompletionContext<'a> {
             exclude_flyimport,
             exclude_traits,
             complete_semicolon,
+            display_target,
         };
         Some((ctx, analysis))
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
index fc2bfc01e62..a03f632cdfd 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
@@ -13,7 +13,7 @@ fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str,
 
     let ty = completion_context
         .expected_type
-        .map(|t| t.display_test(&db).to_string())
+        .map(|t| t.display_test(&db, completion_context.krate.to_display_target(&db)).to_string())
         .unwrap_or("?".to_owned());
 
     let name =
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index b3dd8a8d06e..8d6dc4c8013 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -252,14 +252,16 @@ impl CompletionRelevance {
     /// Provides a relevance score. Higher values are more relevant.
     ///
     /// The absolute value of the relevance score is not meaningful, for
-    /// example a value of 0 doesn't mean "not relevant", rather
+    /// example a value of BASE_SCORE doesn't mean "not relevant", rather
     /// it means "least relevant". The score value should only be used
     /// for relative ordering.
     ///
     /// See is_relevant if you need to make some judgement about score
     /// in an absolute sense.
+    const BASE_SCORE: u32 = u32::MAX / 2;
+
     pub fn score(self) -> u32 {
-        let mut score = !0 / 2;
+        let mut score = Self::BASE_SCORE;
         let CompletionRelevance {
             exact_name_match,
             type_match,
@@ -350,7 +352,7 @@ impl CompletionRelevance {
     /// some threshold such that we think it is especially likely
     /// to be relevant.
     pub fn is_relevant(&self) -> bool {
-        self.score() > 0
+        self.score() > Self::BASE_SCORE
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 4f6c4cb6639..c82905eddef 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -144,7 +144,7 @@ pub(crate) fn render_field(
         is_skipping_completion: receiver.is_some(),
         ..CompletionRelevance::default()
     });
-    item.detail(ty.display(db, ctx.completion.edition).to_string())
+    item.detail(ty.display(db, ctx.completion.display_target).to_string())
         .set_documentation(field.docs(db))
         .set_deprecated(is_deprecated)
         .lookup_by(name);
@@ -212,7 +212,7 @@ pub(crate) fn render_tuple_field(
         field_with_receiver(receiver.as_deref(), &field.to_string()),
         ctx.completion.edition,
     );
-    item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string())
+    item.detail(ty.display(ctx.db(), ctx.completion.display_target).to_string())
         .lookup_by(field.to_string());
     item.set_relevance(CompletionRelevance {
         is_skipping_completion: receiver.is_some(),
@@ -303,7 +303,8 @@ pub(crate) fn render_expr(
 
     let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
-    let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?;
+    let label =
+        expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.display_target).ok()?;
 
     let source_range = match ctx.original_token.parent() {
         Some(node) => match node.ancestors().find_map(ast::Path::cast) {
@@ -318,7 +319,7 @@ pub(crate) fn render_expr(
 
     let snippet = format!(
         "{}$0",
-        expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg, ctx.edition).ok()?
+        expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg, ctx.display_target).ok()?
     );
     let edit = TextEdit::replace(source_range, snippet);
     item.snippet_edit(ctx.config.snippet_cap?, edit);
@@ -398,6 +399,8 @@ fn render_resolution_path(
     let _p = tracing::info_span!("render_resolution_path").entered();
     use hir::ModuleDef::*;
 
+    let krate = ctx.completion.display_target;
+
     match resolution {
         ScopeDef::ModuleDef(Macro(mac)) => {
             let ctx = ctx.import_to_add(import_to_add);
@@ -459,7 +462,7 @@ fn render_resolution_path(
 
     let mut set_item_relevance = |ty: Type| {
         if !ty.is_unknown() {
-            item.detail(ty.display(db, completion.edition).to_string());
+            item.detail(ty.display(db, krate).to_string());
         }
 
         item.set_relevance(CompletionRelevance {
@@ -1151,6 +1154,24 @@ fn main() { Foo::Fo$0 }
                         ),
                         lookup: "Foo{}",
                         detail: "Foo { x: i32, y: i32 }",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            trait_: None,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: true,
+                                    has_self_param: false,
+                                    return_type: DirectConstructor,
+                                },
+                            ),
+                            is_skipping_completion: false,
+                        },
                         trigger_call_info: true,
                     },
                 ]
@@ -1183,6 +1204,24 @@ fn main() { Foo::Fo$0 }
                         ),
                         lookup: "Foo()",
                         detail: "Foo(i32, i32)",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            trait_: None,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: true,
+                                    has_self_param: false,
+                                    return_type: DirectConstructor,
+                                },
+                            ),
+                            is_skipping_completion: false,
+                        },
                         trigger_call_info: true,
                     },
                 ]
@@ -1261,6 +1300,24 @@ fn main() { Foo::Fo$0 }
                             Variant,
                         ),
                         detail: "Foo",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            trait_: None,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: false,
+                                    has_self_param: false,
+                                    return_type: DirectConstructor,
+                                },
+                            ),
+                            is_skipping_completion: false,
+                        },
                         trigger_call_info: true,
                     },
                 ]
@@ -1335,7 +1392,13 @@ fn main() { let _: m::Spam = S$0 }
                             requires_import: false,
                             is_private_editable: false,
                             postfix_match: None,
-                            function: None,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: true,
+                                    has_self_param: false,
+                                    return_type: DirectConstructor,
+                                },
+                            ),
                             is_skipping_completion: false,
                         },
                         trigger_call_info: true,
@@ -1365,7 +1428,13 @@ fn main() { let _: m::Spam = S$0 }
                             requires_import: false,
                             is_private_editable: false,
                             postfix_match: None,
-                            function: None,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: false,
+                                    has_self_param: false,
+                                    return_type: DirectConstructor,
+                                },
+                            ),
                             is_skipping_completion: false,
                         },
                         trigger_call_info: true,
@@ -1590,6 +1659,24 @@ use self::E::*;
                         documentation: Documentation(
                             "variant docs",
                         ),
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            trait_: None,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: false,
+                                    has_self_param: false,
+                                    return_type: DirectConstructor,
+                                },
+                            ),
+                            is_skipping_completion: false,
+                        },
                         trigger_call_info: true,
                     },
                     CompletionItem {
@@ -2081,8 +2168,8 @@ fn main() {
 }
             "#,
             expect![[r#"
-                lc ssss S [type+local]
                 st S S [type]
+                lc ssss S [type+local]
                 st S S [type]
                 ex ssss  [type]
                 ex S  [type]
@@ -2153,14 +2240,14 @@ fn main() {
 }
             "#,
             expect![[r#"
+                st S S []
+                st &S [type]
                 ex core::ops::Deref::deref(&t)  [type_could_unify]
                 lc m i32 [local]
                 lc t T [local]
                 lc &t [type+local]
                 st S S []
                 st &S [type]
-                st S S []
-                st &S [type]
                 st T T []
                 st &T [type]
                 fn foo(…) fn(&S) []
@@ -2202,14 +2289,14 @@ fn main() {
 }
             "#,
             expect![[r#"
+                st S S []
+                st &mut S [type]
                 ex core::ops::DerefMut::deref_mut(&mut t)  [type_could_unify]
                 lc m i32 [local]
                 lc t T [local]
                 lc &mut t [type+local]
                 st S S []
                 st &mut S [type]
-                st S S []
-                st &mut S [type]
                 st T T []
                 st &mut T [type]
                 fn foo(…) fn(&mut S) []
@@ -2306,9 +2393,9 @@ fn main() {
 }
 "#,
             expect![[r#"
-                ex core::ops::Deref::deref(&bar())  [type_could_unify]
                 st S S []
                 st &S [type]
+                ex core::ops::Deref::deref(&bar())  [type_could_unify]
                 st S S []
                 st &S [type]
                 st T T []
@@ -2686,10 +2773,12 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
                                 Indel {
                                     insert: "(",
                                     delete: 107..107,
+                                    annotation: None,
                                 },
                                 Indel {
                                     insert: "qux)()",
                                     delete: 109..110,
+                                    annotation: None,
                                 },
                             ],
                         },
@@ -2827,11 +2916,11 @@ fn foo() {
 }
 "#,
             expect![[r#"
+                ev Foo::B Foo::B [type_could_unify]
+                ev Foo::A(…) Foo::A(T) [type_could_unify]
                 lc foo Foo<u32> [type+local]
                 ex foo  [type]
                 ex Foo::B  [type]
-                ev Foo::A(…) Foo::A(T) [type_could_unify]
-                ev Foo::B Foo::B [type_could_unify]
                 en Foo Foo<{unknown}> [type_could_unify]
                 fn foo() fn() []
                 fn bar() fn() -> Foo<u8> []
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
index e357ab24d22..f11b3023679 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
@@ -16,7 +16,7 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem>
     let name = const_.name(db)?;
     let (name, escaped_name) =
         (name.as_str().to_smolstr(), name.display(db, ctx.completion.edition).to_smolstr());
-    let detail = const_.display(db, ctx.completion.edition).to_string();
+    let detail = const_.display(db, ctx.completion.display_target).to_string();
 
     let mut item =
         CompletionItem::new(SymbolKind::Const, ctx.source_range(), name, ctx.completion.edition);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index fd90613964a..4693bdc047f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -4,7 +4,7 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
 use ide_db::{SnippetCap, SymbolKind};
 use itertools::Itertools;
 use stdx::{format_to, to_lower_snake_case};
-use syntax::{format_smolstr, AstNode, Edition, SmolStr, ToSmolStr};
+use syntax::{format_smolstr, AstNode, SmolStr, ToSmolStr};
 
 use crate::{
     context::{
@@ -142,9 +142,9 @@ fn render(
     }
 
     let detail = if ctx.completion.config.full_function_signatures {
-        detail_full(db, func, ctx.completion.edition)
+        detail_full(ctx.completion, func)
     } else {
-        detail(ctx.completion, func, ctx.completion.edition)
+        detail(ctx.completion, func)
     };
     item.set_documentation(ctx.docs(func))
         .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
@@ -251,7 +251,7 @@ pub(super) fn add_call_parens<'b>(
                     format!(
                         "{}(${{1:{}}}{}{})$0",
                         escaped_name,
-                        self_param.display(ctx.db, ctx.edition),
+                        self_param.display(ctx.db, ctx.display_target),
                         if params.is_empty() { "" } else { ", " },
                         function_params_snippet
                     )
@@ -307,7 +307,7 @@ fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'sta
     ""
 }
 
-fn detail(ctx: &CompletionContext<'_>, func: hir::Function, edition: Edition) -> String {
+fn detail(ctx: &CompletionContext<'_>, func: hir::Function) -> String {
     let mut ret_ty = func.ret_type(ctx.db);
     let mut detail = String::new();
 
@@ -324,15 +324,15 @@ fn detail(ctx: &CompletionContext<'_>, func: hir::Function, edition: Edition) ->
         format_to!(detail, "unsafe ");
     }
 
-    format_to!(detail, "fn({})", params_display(ctx.db, func, edition));
+    format_to!(detail, "fn({})", params_display(ctx, func));
     if !ret_ty.is_unit() {
-        format_to!(detail, " -> {}", ret_ty.display(ctx.db, edition));
+        format_to!(detail, " -> {}", ret_ty.display(ctx.db, ctx.display_target));
     }
     detail
 }
 
-fn detail_full(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String {
-    let signature = format!("{}", func.display(db, edition));
+fn detail_full(ctx: &CompletionContext<'_>, func: hir::Function) -> String {
+    let signature = format!("{}", func.display(ctx.db, ctx.display_target));
     let mut detail = String::with_capacity(signature.len());
 
     for segment in signature.split_whitespace() {
@@ -346,24 +346,24 @@ fn detail_full(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> S
     detail
 }
 
-fn params_display(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String {
-    if let Some(self_param) = func.self_param(db) {
-        let assoc_fn_params = func.assoc_fn_params(db);
+fn params_display(ctx: &CompletionContext<'_>, func: hir::Function) -> String {
+    if let Some(self_param) = func.self_param(ctx.db) {
+        let assoc_fn_params = func.assoc_fn_params(ctx.db);
         let params = assoc_fn_params
             .iter()
             .skip(1) // skip the self param because we are manually handling that
-            .map(|p| p.ty().display(db, edition));
+            .map(|p| p.ty().display(ctx.db, ctx.display_target));
         format!(
             "{}{}",
-            self_param.display(db, edition),
+            self_param.display(ctx.db, ctx.display_target),
             params.format_with("", |display, f| {
                 f(&", ")?;
                 f(&display)
             })
         )
     } else {
-        let assoc_fn_params = func.assoc_fn_params(db);
-        assoc_fn_params.iter().map(|p| p.ty().display(db, edition)).join(", ")
+        let assoc_fn_params = func.assoc_fn_params(ctx.db);
+        assoc_fn_params.iter().map(|p| p.ty().display(ctx.db, ctx.display_target)).join(", ")
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index aab54ca5e01..ffda52fb478 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -8,7 +8,7 @@ use ide_db::{
 
 use crate::{
     context::{CompletionContext, PathCompletionCtx, PathKind},
-    item::{Builder, CompletionItem},
+    item::{Builder, CompletionItem, CompletionRelevanceFn},
     render::{
         compute_type_match,
         variant::{
@@ -17,7 +17,7 @@ use crate::{
         },
         RenderContext,
     },
-    CompletionItemKind, CompletionRelevance,
+    CompletionItemKind, CompletionRelevance, CompletionRelevanceReturnType,
 };
 
 pub(crate) fn render_variant_lit(
@@ -82,10 +82,10 @@ fn render(
 
     let mut rendered = match kind {
         StructKind::Tuple if should_add_parens => {
-            render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name, completion.edition)
+            render_tuple_lit(completion, snippet_cap, &fields, &escaped_qualified_name)
         }
         StructKind::Record if should_add_parens => {
-            render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name, completion.edition)
+            render_record_lit(completion, snippet_cap, &fields, &escaped_qualified_name)
         }
         _ => RenderedLiteral {
             literal: escaped_qualified_name.clone(),
@@ -131,6 +131,12 @@ fn render(
     let ty = thing.ty(db);
     item.set_relevance(CompletionRelevance {
         type_match: compute_type_match(ctx.completion, &ty),
+        // function is a misnomer here, this is more about constructor information
+        function: Some(CompletionRelevanceFn {
+            has_params: !fields.is_empty(),
+            has_self_param: false,
+            return_type: CompletionRelevanceReturnType::DirectConstructor,
+        }),
         ..ctx.completion_relevance()
     });
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index e265e92f979..8b2476d153f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -62,7 +62,7 @@ fn render(
         completion.edition,
     );
     item.set_deprecated(ctx.is_deprecated(macro_))
-        .detail(macro_.display(completion.db, completion.edition).to_string())
+        .detail(macro_.display(completion.db, completion.display_target).to_string())
         .set_documentation(docs)
         .set_relevance(ctx.completion_relevance());
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
index 1b952f31360..d57feee4fa6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
@@ -38,7 +38,7 @@ fn render(
     } else {
         (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr())
     };
-    let detail = type_alias.display(db, ctx.completion.edition).to_string();
+    let detail = type_alias.display(db, ctx.completion.display_target).to_string();
 
     let mut item = CompletionItem::new(
         SymbolKind::TypeAlias,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
index 74203626521..09154e81c03 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
@@ -88,7 +88,7 @@ pub(crate) fn render_union_literal(
             f(&format_args!(
                 "{}: {}",
                 field.name(ctx.db()).display(ctx.db(), ctx.completion.edition),
-                field.ty(ctx.db()).display(ctx.db(), ctx.completion.edition)
+                field.ty(ctx.db()).display(ctx.db(), ctx.completion.display_target)
             ))
         }),
         if fields_omitted { ", .." } else { "" }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
index d8516ea1078..83718e57229 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
@@ -1,10 +1,10 @@
 //! Code common to structs, unions, and enum variants.
 
 use crate::context::CompletionContext;
-use hir::{db::HirDatabase, sym, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind};
+use hir::{sym, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind};
 use ide_db::SnippetCap;
 use itertools::Itertools;
-use syntax::{Edition, SmolStr};
+use syntax::SmolStr;
 
 /// A rendered struct, union, or enum variant, split into fields for actual
 /// auto-completion (`literal`, using `field: ()`) and display in the
@@ -17,11 +17,10 @@ pub(crate) struct RenderedLiteral {
 /// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for
 /// the `name` argument for an anonymous type.
 pub(crate) fn render_record_lit(
-    db: &dyn HirDatabase,
+    ctx: &CompletionContext<'_>,
     snippet_cap: Option<SnippetCap>,
     fields: &[hir::Field],
     path: &str,
-    edition: Edition,
 ) -> RenderedLiteral {
     if snippet_cap.is_none() {
         return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
@@ -30,19 +29,19 @@ pub(crate) fn render_record_lit(
         if snippet_cap.is_some() {
             f(&format_args!(
                 "{}: ${{{}:()}}",
-                field.name(db).display(db.upcast(), edition),
+                field.name(ctx.db).display(ctx.db, ctx.edition),
                 idx + 1
             ))
         } else {
-            f(&format_args!("{}: ()", field.name(db).display(db.upcast(), edition)))
+            f(&format_args!("{}: ()", field.name(ctx.db).display(ctx.db, ctx.edition)))
         }
     });
 
     let types = fields.iter().format_with(", ", |field, f| {
         f(&format_args!(
             "{}: {}",
-            field.name(db).display(db.upcast(), edition),
-            field.ty(db).display(db, edition)
+            field.name(ctx.db).display(ctx.db, ctx.edition),
+            field.ty(ctx.db).display(ctx.db, ctx.display_target)
         ))
     });
 
@@ -55,11 +54,10 @@ pub(crate) fn render_record_lit(
 /// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for
 /// the `name` argument for an anonymous type.
 pub(crate) fn render_tuple_lit(
-    db: &dyn HirDatabase,
+    ctx: &CompletionContext<'_>,
     snippet_cap: Option<SnippetCap>,
     fields: &[hir::Field],
     path: &str,
-    edition: Edition,
 ) -> RenderedLiteral {
     if snippet_cap.is_none() {
         return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
@@ -72,7 +70,9 @@ pub(crate) fn render_tuple_lit(
         }
     });
 
-    let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db, edition)));
+    let types = fields
+        .iter()
+        .format_with(", ", |field, f| f(&field.ty(ctx.db).display(ctx.db, ctx.display_target)));
 
     RenderedLiteral {
         literal: format!("{path}({completions})"),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 37557512837..9b3c676c48a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -170,6 +170,7 @@ impl Unit {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -247,6 +248,7 @@ fn complete_in_block() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -297,6 +299,7 @@ fn complete_after_if_expr() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -370,6 +373,7 @@ fn completes_in_loop_ctx() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -942,6 +946,7 @@ fn foo() { if foo {} $0 }
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -983,6 +988,7 @@ fn foo() { if foo {} el$0 }
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1072,6 +1078,7 @@ fn foo() { if foo {} $0 let x = 92; }
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1113,6 +1120,7 @@ fn foo() { if foo {} el$0 let x = 92; }
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1154,6 +1162,7 @@ fn foo() { if foo {} el$0 { let x = 92; } }
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1205,6 +1214,7 @@ pub struct UnstableThisShouldNotBeListed;
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1258,6 +1268,7 @@ pub struct UnstableButWeAreOnNightlyAnyway;
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1495,6 +1506,7 @@ fn main() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1920,6 +1932,7 @@ fn bar() {
             md rust_2015 (use core::prelude::rust_2015)
             md rust_2018 (use core::prelude::rust_2018)
             md rust_2021 (use core::prelude::rust_2021)
+            md rust_2024 (use core::prelude::rust_2024)
             tt Clone
             tt Copy
             tt IntoIterator
@@ -1944,6 +1957,7 @@ fn bar() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -2015,6 +2029,7 @@ fn foo() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
index bea6d60769c..be2c37d1016 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
@@ -285,6 +285,7 @@ fn bar() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index 2b05184bdbe..005263d100a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1009,6 +1009,7 @@ fn here_we_go() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1059,6 +1060,7 @@ fn here_we_go() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1182,6 +1184,7 @@ fn bar() { qu$0 }
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
@@ -1437,6 +1440,7 @@ fn foo() {
             kw if let
             kw impl
             kw let
+            kw letm
             kw loop
             kw match
             kw mod
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 6f71c3d9bd7..502314ed1e0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -12,11 +12,11 @@ use arrayvec::ArrayVec;
 use either::Either;
 use hir::{
     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
-    Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
-    Function, GenericDef, GenericParam, GenericSubstitution, HasContainer, HasVisibility,
-    HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, ModuleDef,
-    Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, TraitAlias,
-    TupleField, TypeAlias, Variant, VariantDef, Visibility,
+    Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, ExternAssocItem,
+    ExternCrateDecl, Field, Function, GenericDef, GenericParam, GenericSubstitution, HasContainer,
+    HasVisibility, HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module,
+    ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait,
+    TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
 };
 use span::Edition;
 use stdx::{format_to, impl_from};
@@ -207,7 +207,7 @@ impl Definition {
         &self,
         db: &RootDatabase,
         famous_defs: Option<&FamousDefs<'_, '_>>,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> Option<Documentation> {
         let docs = match self {
             Definition::Macro(it) => it.docs(db),
@@ -228,7 +228,7 @@ impl Definition {
                     let docs = adt.docs(db)?;
                     let docs = format!(
                         "*This is the documentation for* `{}`\n\n{}",
-                        adt.display(db, edition),
+                        adt.display(db, display_target),
                         docs.as_str()
                     );
                     Some(Documentation::new(docs))
@@ -237,8 +237,9 @@ impl Definition {
             Definition::BuiltinType(it) => {
                 famous_defs.and_then(|fd| {
                     // std exposes prim_{} modules with docstrings on the root to document the builtins
-                    let primitive_mod = format!("prim_{}", it.name().display(fd.0.db, edition));
-                    let doc_owner = find_std_module(fd, &primitive_mod, edition)?;
+                    let primitive_mod =
+                        format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
+                    let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
                     doc_owner.docs(fd.0.db)
                 })
             }
@@ -256,16 +257,21 @@ impl Definition {
                 let AttributeTemplate { word, list, name_value_str } = it.template(db)?;
                 let mut docs = "Valid forms are:".to_owned();
                 if word {
-                    format_to!(docs, "\n - #\\[{}]", name.display(db, edition));
+                    format_to!(docs, "\n - #\\[{}]", name.display(db, display_target.edition));
                 }
                 if let Some(list) = list {
-                    format_to!(docs, "\n - #\\[{}({})]", name.display(db, edition), list);
+                    format_to!(
+                        docs,
+                        "\n - #\\[{}({})]",
+                        name.display(db, display_target.edition),
+                        list
+                    );
                 }
                 if let Some(name_value_str) = name_value_str {
                     format_to!(
                         docs,
                         "\n - #\\[{} = {}]",
-                        name.display(db, edition),
+                        name.display(db, display_target.edition),
                         name_value_str
                     );
                 }
@@ -288,49 +294,60 @@ impl Definition {
         })
     }
 
-    pub fn label(&self, db: &RootDatabase, edition: Edition) -> String {
+    pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
         match *self {
-            Definition::Macro(it) => it.display(db, edition).to_string(),
-            Definition::Field(it) => it.display(db, edition).to_string(),
-            Definition::TupleField(it) => it.display(db, edition).to_string(),
-            Definition::Module(it) => it.display(db, edition).to_string(),
-            Definition::Crate(it) => it.display(db, edition).to_string(),
-            Definition::Function(it) => it.display(db, edition).to_string(),
-            Definition::Adt(it) => it.display(db, edition).to_string(),
-            Definition::Variant(it) => it.display(db, edition).to_string(),
-            Definition::Const(it) => it.display(db, edition).to_string(),
-            Definition::Static(it) => it.display(db, edition).to_string(),
-            Definition::Trait(it) => it.display(db, edition).to_string(),
-            Definition::TraitAlias(it) => it.display(db, edition).to_string(),
-            Definition::TypeAlias(it) => it.display(db, edition).to_string(),
-            Definition::BuiltinType(it) => it.name().display(db, edition).to_string(),
-            Definition::BuiltinLifetime(it) => it.name().display(db, edition).to_string(),
+            Definition::Macro(it) => it.display(db, display_target).to_string(),
+            Definition::Field(it) => it.display(db, display_target).to_string(),
+            Definition::TupleField(it) => it.display(db, display_target).to_string(),
+            Definition::Module(it) => it.display(db, display_target).to_string(),
+            Definition::Crate(it) => it.display(db, display_target).to_string(),
+            Definition::Function(it) => it.display(db, display_target).to_string(),
+            Definition::Adt(it) => it.display(db, display_target).to_string(),
+            Definition::Variant(it) => it.display(db, display_target).to_string(),
+            Definition::Const(it) => it.display(db, display_target).to_string(),
+            Definition::Static(it) => it.display(db, display_target).to_string(),
+            Definition::Trait(it) => it.display(db, display_target).to_string(),
+            Definition::TraitAlias(it) => it.display(db, display_target).to_string(),
+            Definition::TypeAlias(it) => it.display(db, display_target).to_string(),
+            Definition::BuiltinType(it) => {
+                it.name().display(db, display_target.edition).to_string()
+            }
+            Definition::BuiltinLifetime(it) => {
+                it.name().display(db, display_target.edition).to_string()
+            }
             Definition::Local(it) => {
                 let ty = it.ty(db);
-                let ty_display = ty.display_truncated(db, None, edition);
+                let ty_display = ty.display_truncated(db, None, display_target);
                 let is_mut = if it.is_mut(db) { "mut " } else { "" };
                 if it.is_self(db) {
                     format!("{is_mut}self: {ty_display}")
                 } else {
                     let name = it.name(db);
                     let let_kw = if it.is_param(db) { "" } else { "let " };
-                    format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db, edition))
+                    format!(
+                        "{let_kw}{is_mut}{}: {ty_display}",
+                        name.display(db, display_target.edition)
+                    )
                 }
             }
             Definition::SelfType(impl_def) => {
                 let self_ty = &impl_def.self_ty(db);
                 match self_ty.as_adt() {
-                    Some(it) => it.display(db, edition).to_string(),
-                    None => self_ty.display(db, edition).to_string(),
+                    Some(it) => it.display(db, display_target).to_string(),
+                    None => self_ty.display(db, display_target).to_string(),
                 }
             }
-            Definition::GenericParam(it) => it.display(db, edition).to_string(),
-            Definition::Label(it) => it.name(db).display(db, edition).to_string(),
-            Definition::ExternCrateDecl(it) => it.display(db, edition).to_string(),
-            Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db, edition)),
-            Definition::ToolModule(it) => it.name(db).display(db, edition).to_string(),
+            Definition::GenericParam(it) => it.display(db, display_target).to_string(),
+            Definition::Label(it) => it.name(db).display(db, display_target.edition).to_string(),
+            Definition::ExternCrateDecl(it) => it.display(db, display_target).to_string(),
+            Definition::BuiltinAttr(it) => {
+                format!("#[{}]", it.name(db).display(db, display_target.edition))
+            }
+            Definition::ToolModule(it) => {
+                it.name(db).display(db, display_target.edition).to_string()
+            }
             Definition::DeriveHelper(it) => {
-                format!("derive_helper {}", it.name(db).display(db, edition))
+                format!("derive_helper {}", it.name(db).display(db, display_target.edition))
             }
             // FIXME
             Definition::InlineAsmRegOrRegClass(_) => "inline_asm_reg_or_reg_class".to_owned(),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 9c983e7c4a6..0a7a7d1fb24 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -15052,7 +15052,7 @@ cannot be represented as the underlying type without loss."##,
     },
     Lint {
         label: "clippy::manual_bits",
-        description: r##"Checks for usage of `std::mem::size_of::<T>() * 8` when
+        description: r##"Checks for usage of `size_of::<T>() * 8` when
 `T::BITS` is available."##,
         default_severity: Severity::Allow,
         warn_since: None,
@@ -17394,7 +17394,7 @@ count of elements of type `T`"##,
     },
     Lint {
         label: "clippy::size_of_ref",
-        description: r##"Checks for calls to `std::mem::size_of_val()` where the argument is
+        description: r##"Checks for calls to `size_of_val()` where the argument is
 a reference to a reference."##,
         default_severity: Severity::Allow,
         warn_since: None,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 126b30470b7..a348a4ef7d3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -192,7 +192,9 @@ impl<'a> PathTransform<'a> {
                     }
                 }
                 (Either::Left(k), None) => {
-                    if let Some(default) = k.default(db, target_edition) {
+                    if let Some(default) =
+                        k.default(db, target_module.krate().to_display_target(db))
+                    {
                         if let Some(default) = default.expr() {
                             const_substs.insert(k, default.syntax().clone_for_update());
                             defaulted_params.push(Either::Right(k));
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 59914bedde4..1633065f652 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -22,7 +22,10 @@
 //! Our current behavior is ¯\_(ツ)_/¯.
 use std::fmt;
 
-use crate::text_edit::{TextEdit, TextEditBuilder};
+use crate::{
+    source_change::ChangeAnnotation,
+    text_edit::{TextEdit, TextEditBuilder},
+};
 use base_db::AnchoredPathBuf;
 use either::Either;
 use hir::{FieldSource, FileRange, HirFileIdExt, InFile, ModuleSource, Semantics};
@@ -365,10 +368,12 @@ fn rename_reference(
     }));
 
     let mut insert_def_edit = |def| {
-        let (file_id, edit) = source_edit_from_def(sema, def, new_name)?;
+        let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?;
         source_change.insert_source_edit(file_id, edit);
         Ok(())
     };
+    // This needs to come after the references edits, because we change the annotation of existing edits
+    // if a conflict is detected.
     insert_def_edit(def)?;
     Ok(source_change)
 }
@@ -537,6 +542,7 @@ fn source_edit_from_def(
     sema: &Semantics<'_, RootDatabase>,
     def: Definition,
     new_name: &str,
+    source_change: &mut SourceChange,
 ) -> Result<(FileId, TextEdit)> {
     let new_name_edition_aware = |new_name: &str, file_id: EditionedFileId| {
         if is_raw_identifier(new_name, file_id.edition()) {
@@ -548,6 +554,23 @@ fn source_edit_from_def(
     let mut edit = TextEdit::builder();
     if let Definition::Local(local) = def {
         let mut file_id = None;
+
+        let conflict_annotation = if !sema.rename_conflicts(&local, new_name).is_empty() {
+            Some(
+                source_change.insert_annotation(ChangeAnnotation {
+                    label: "This rename will change the program's meaning".to_owned(),
+                    needs_confirmation: true,
+                    description: Some(
+                        "Some variable(s) will shadow the renamed variable \
+                        or be shadowed by it if the rename is performed"
+                            .to_owned(),
+                    ),
+                }),
+            )
+        } else {
+            None
+        };
+
         for source in local.sources(sema.db) {
             let source = match source.source.clone().original_ast_node_rooted(sema.db) {
                 Some(source) => source,
@@ -611,8 +634,15 @@ fn source_edit_from_def(
                 }
             }
         }
+        let mut edit = edit.finish();
+
+        for (edit, _) in source_change.source_file_edits.values_mut() {
+            edit.set_annotation(conflict_annotation);
+        }
+        edit.set_annotation(conflict_annotation);
+
         let Some(file_id) = file_id else { bail!("No file available to rename") };
-        return Ok((EditionedFileId::file_id(file_id), edit.finish()));
+        return Ok((EditionedFileId::file_id(file_id), edit));
     }
     let FileRange { file_id, range } = def
         .range_for_rename(sema)
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 34642d7eaf9..b4d0b0dc9f0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -3,7 +3,7 @@
 //!
 //! It can be viewed as a dual for `Change`.
 
-use std::{collections::hash_map::Entry, iter, mem};
+use std::{collections::hash_map::Entry, fmt, iter, mem};
 
 use crate::text_edit::{TextEdit, TextEditBuilder};
 use crate::{assists::Command, syntax_helpers::tree_diff::diff, SnippetCap};
@@ -18,23 +18,33 @@ use syntax::{
     AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
 };
 
+/// An annotation ID associated with an indel, to describe changes.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ChangeAnnotationId(u32);
+
+impl fmt::Display for ChangeAnnotationId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.0, f)
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct ChangeAnnotation {
+    pub label: String,
+    pub needs_confirmation: bool,
+    pub description: Option<String>,
+}
+
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
     pub source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>,
     pub file_system_edits: Vec<FileSystemEdit>,
     pub is_snippet: bool,
+    pub annotations: FxHashMap<ChangeAnnotationId, ChangeAnnotation>,
+    next_annotation_id: u32,
 }
 
 impl SourceChange {
-    /// Creates a new SourceChange with the given label
-    /// from the edits.
-    pub fn from_edits(
-        source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>,
-        file_system_edits: Vec<FileSystemEdit>,
-    ) -> Self {
-        SourceChange { source_file_edits, file_system_edits, is_snippet: false }
-    }
-
     pub fn from_text_edit(file_id: impl Into<FileId>, edit: TextEdit) -> Self {
         SourceChange {
             source_file_edits: iter::once((file_id.into(), (edit, None))).collect(),
@@ -42,6 +52,13 @@ impl SourceChange {
         }
     }
 
+    pub fn insert_annotation(&mut self, annotation: ChangeAnnotation) -> ChangeAnnotationId {
+        let id = ChangeAnnotationId(self.next_annotation_id);
+        self.next_annotation_id += 1;
+        self.annotations.insert(id, annotation);
+        id
+    }
+
     /// Inserts a [`TextEdit`] for the given [`FileId`]. This properly handles merging existing
     /// edits for a file if some already exist.
     pub fn insert_source_edit(&mut self, file_id: impl Into<FileId>, edit: TextEdit) {
@@ -120,7 +137,12 @@ impl From<IntMap<FileId, TextEdit>> for SourceChange {
     fn from(source_file_edits: IntMap<FileId, TextEdit>) -> SourceChange {
         let source_file_edits =
             source_file_edits.into_iter().map(|(file_id, edit)| (file_id, (edit, None))).collect();
-        SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
+        SourceChange {
+            source_file_edits,
+            file_system_edits: Vec::new(),
+            is_snippet: false,
+            ..SourceChange::default()
+        }
     }
 }
 
@@ -482,6 +504,7 @@ impl From<FileSystemEdit> for SourceChange {
             source_file_edits: Default::default(),
             file_system_edits: vec![edit],
             is_snippet: false,
+            ..SourceChange::default()
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index bb4c289c908..2737436993d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -24,7 +24,6 @@ use std::{
     cmp::Ordering,
     fmt,
     hash::{Hash, Hasher},
-    mem,
     ops::ControlFlow,
 };
 
@@ -299,7 +298,7 @@ impl SymbolIndex {
     }
 
     pub fn memory_size(&self) -> usize {
-        self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
+        self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol>()
     }
 
     fn range_to_map_value(start: usize, end: usize) -> u64 {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index 74c0b8e2baa..0b2e8aa6836 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -1,4 +1,6 @@
 //! Various helper functions to work with SyntaxNodes.
+use std::ops::ControlFlow;
+
 use itertools::Itertools;
 use parser::T;
 use span::Edition;
@@ -119,7 +121,10 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
         match ast::Stmt::cast(node.clone()) {
             Some(ast::Stmt::LetStmt(l)) => {
                 if let Some(pat) = l.pat() {
-                    walk_pat(&pat, cb);
+                    walk_pat(&pat, &mut |pat| {
+                        cb(pat);
+                        ControlFlow::<(), ()>::Continue(())
+                    });
                 }
                 if let Some(expr) = l.initializer() {
                     walk_patterns_in_expr(&expr, cb);
@@ -154,7 +159,10 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
                     }
                 } else if let Some(pat) = ast::Pat::cast(node) {
                     preorder.skip_subtree();
-                    walk_pat(&pat, cb);
+                    walk_pat(&pat, &mut |pat| {
+                        cb(pat);
+                        ControlFlow::<(), ()>::Continue(())
+                    });
                 }
             }
         }
@@ -162,7 +170,10 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
 }
 
 /// Preorder walk all the pattern's sub patterns.
-pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
+pub fn walk_pat<T>(
+    pat: &ast::Pat,
+    cb: &mut dyn FnMut(ast::Pat) -> ControlFlow<T>,
+) -> ControlFlow<T> {
     let mut preorder = pat.syntax().preorder();
     while let Some(event) = preorder.next() {
         let node = match event {
@@ -173,10 +184,10 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
         match ast::Pat::cast(node) {
             Some(pat @ ast::Pat::ConstBlockPat(_)) => {
                 preorder.skip_subtree();
-                cb(pat);
+                cb(pat)?;
             }
             Some(pat) => {
-                cb(pat);
+                cb(pat)?;
             }
             // skip const args
             None if ast::GenericArg::can_cast(kind) => {
@@ -185,6 +196,7 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
             None => (),
         }
     }
+    ControlFlow::Continue(())
 }
 
 /// Preorder walk all the type's sub types.
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
index 0c675f0619f..b59010f2f8c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
@@ -8,6 +8,8 @@ use itertools::Itertools;
 pub use span::{TextRange, TextSize};
 use std::cmp::max;
 
+use crate::source_change::ChangeAnnotationId;
+
 /// `InsertDelete` -- a single "atomic" change to text
 ///
 /// Must not overlap with other `InDel`s
@@ -16,6 +18,7 @@ pub struct Indel {
     pub insert: String,
     /// Refers to offsets in the original text
     pub delete: TextRange,
+    pub annotation: Option<ChangeAnnotationId>,
 }
 
 #[derive(Default, Debug, Clone)]
@@ -37,7 +40,7 @@ impl Indel {
         Indel::replace(range, String::new())
     }
     pub fn replace(range: TextRange, replace_with: String) -> Indel {
-        Indel { delete: range, insert: replace_with }
+        Indel { delete: range, insert: replace_with, annotation: None }
     }
 
     pub fn apply(&self, text: &mut String) {
@@ -138,6 +141,14 @@ impl TextEdit {
         }
         Some(res)
     }
+
+    pub fn set_annotation(&mut self, annotation: Option<ChangeAnnotationId>) {
+        if annotation.is_some() {
+            for indel in &mut self.indels {
+                indel.annotation = annotation;
+            }
+        }
+    }
 }
 
 impl IntoIterator for TextEdit {
@@ -180,7 +191,7 @@ impl TextEditBuilder {
     pub fn invalidates_offset(&self, offset: TextSize) -> bool {
         self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset))
     }
-    fn indel(&mut self, indel: Indel) {
+    pub fn indel(&mut self, indel: Indel) {
         self.indels.push(indel);
         if self.indels.len() <= 16 {
             assert_disjoint_or_equal(&mut self.indels);
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index e3a1e12e029..af25c2b2e33 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -12,7 +12,7 @@ pub(crate) fn expected_function(
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0618"),
-        format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.edition)),
+        format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.display_target)),
         d.call.map(|it| it.into()),
     )
     .experimental()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 5730508436d..82cd1f2fde6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -8,7 +8,7 @@ macro_rules! format_ty {
             $fmt,
             $(
                 $arg
-                    .display($ctx.sema.db, $ctx.edition)
+                    .display($ctx.sema.db, $ctx.display_target)
                     .with_closure_style(ClosureStyle::ClosureWithId)
             ),*
         )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index a9ff06fb0ab..7d0f10983d7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -8,7 +8,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0507"),
-        format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.edition)),
+        format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.display_target)),
         d.span,
     )
     .experimental() // spans are broken, and I'm not sure how precise we can detect copy types
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 1363a8ff0dd..3db2e013a39 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -30,7 +30,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
             (
                 format!("`fn {redundant_assoc_item_name}`"),
                 function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
-                format!("\n    {};", function.display(db, ctx.edition)),
+                format!("\n    {};", function.display(db, ctx.display_target)),
             )
         }
         hir::AssocItem::Const(id) => {
@@ -38,7 +38,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
             (
                 format!("`const {redundant_assoc_item_name}`"),
                 constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
-                format!("\n    {};", constant.display(db, ctx.edition)),
+                format!("\n    {};", constant.display(db, ctx.display_target)),
             )
         }
         hir::AssocItem::TypeAlias(id) => {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 7cf8282d052..c726a3bcd3c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -45,10 +45,10 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         format!(
             "expected {}, found {}",
             d.expected
-                .display(ctx.sema.db, ctx.edition)
+                .display(ctx.sema.db, ctx.display_target)
                 .with_closure_style(ClosureStyle::ClosureWithId),
             d.actual
-                .display(ctx.sema.db, ctx.edition)
+                .display(ctx.sema.db, ctx.display_target)
                 .with_closure_style(ClosureStyle::ClosureWithId),
         ),
         display_range,
@@ -306,8 +306,8 @@ fn str_ref_to_owned(
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
-    let expected = d.expected.display(ctx.sema.db, ctx.edition);
-    let actual = d.actual.display(ctx.sema.db, ctx.edition);
+    let expected = d.expected.display(ctx.sema.db, ctx.display_target);
+    let actual = d.actual.display(ctx.sema.db, ctx.display_target);
 
     // FIXME do this properly
     if expected.to_string() != "String" || actual.to_string() != "&str" {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index b023a95fb35..c25318eda48 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -27,7 +27,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
             format!(
                 "invalid `_` expression, expected type `{}`",
                 d.expected
-                    .display(ctx.sema.db, ctx.edition)
+                    .display(ctx.sema.db, ctx.display_target)
                     .with_closure_style(ClosureStyle::ClosureWithId),
             ),
             fixes(ctx, d),
@@ -72,7 +72,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
                     prefer_absolute: ctx.config.prefer_absolute,
                     allow_unstable: ctx.is_nightly,
                 },
-                ctx.edition,
+                ctx.display_target,
             )
             .ok()
         })
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index dfb03eee732..6ab713a5896 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -38,7 +38,7 @@ pub(crate) fn unresolved_field(
         format!(
             "no field `{}` on type `{}`{method_suffix}",
             d.name.display(ctx.sema.db, ctx.edition),
-            d.receiver.display(ctx.sema.db, ctx.edition)
+            d.receiver.display(ctx.sema.db, ctx.display_target)
         ),
         adjusted_display_range(ctx, d.expr, &|expr| {
             Some(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index e4de107249b..35e7521af70 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -31,7 +31,7 @@ pub(crate) fn unresolved_method(
         format!(
             "no method `{}` on type `{}`{suffix}",
             d.name.display(ctx.sema.db, ctx.edition),
-            d.receiver.display(ctx.sema.db, ctx.edition)
+            d.receiver.display(ctx.sema.db, ctx.display_target)
         ),
         adjusted_display_range(ctx, d.expr, &|expr| {
             Some(
@@ -152,7 +152,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
             receiver_type.as_adt()?.name(db).display_no_db(ctx.edition).to_smolstr();
 
         let generic_parameters: Vec<SmolStr> =
-            receiver_type.generic_parameters(db, ctx.edition).collect();
+            receiver_type.generic_parameters(db, ctx.display_target).collect();
         // if receiver should be pass as first arg in the assoc func,
         // we could omit generic parameters cause compiler can deduce it automatically
         if !need_to_take_receiver_as_first_arg && !generic_parameters.is_empty() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 0a55b6e9bee..e15d3495789 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -81,7 +81,10 @@ mod tests;
 use std::{collections::hash_map, iter, sync::LazyLock};
 
 use either::Either;
-use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics};
+use hir::{
+    db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, DisplayTarget, HirFileId, InFile,
+    Semantics,
+};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
     base_db::{ReleaseChannel, SourceDatabase},
@@ -277,6 +280,7 @@ struct DiagnosticsContext<'a> {
     sema: Semantics<'a, RootDatabase>,
     resolve: &'a AssistResolveStrategy,
     edition: Edition,
+    display_target: DisplayTarget,
     is_nightly: bool,
 }
 
@@ -374,7 +378,18 @@ pub fn semantic_diagnostics(
         module.and_then(|m| db.toolchain_channel(m.krate().into())),
         Some(ReleaseChannel::Nightly) | None
     );
-    let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition(), is_nightly };
+    let krate = module.map(|module| module.krate()).unwrap_or_else(|| {
+        (*db.crate_graph().crates_in_topological_order().last().unwrap()).into()
+    });
+    let display_target = krate.to_display_target(db);
+    let ctx = DiagnosticsContext {
+        config,
+        sema,
+        resolve,
+        edition: file_id.edition(),
+        is_nightly,
+        display_target,
+    };
 
     let mut diags = Vec::new();
     match module {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 4bead14e31d..e219ba4bf63 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -7,8 +7,7 @@ use crate::{
     SsrMatches,
 };
 use hir::{FileRange, ImportPathConfig, Semantics};
-use ide_db::FxHashMap;
-use parser::Edition;
+use ide_db::{base_db::SourceDatabase, FxHashMap};
 use std::{cell::Cell, iter::Peekable};
 use syntax::{
     ast::{self, AstNode, AstToken, HasGenericArgs},
@@ -627,22 +626,23 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
                 match_error!("Failed to get receiver type for `{}`", expr.syntax().text())
             })?
             .original;
-        let edition = self
-            .sema
-            .scope(expr.syntax())
-            .map(|it| it.krate().edition(self.sema.db))
-            .unwrap_or(Edition::CURRENT);
-        // Temporary needed to make the borrow checker happy.
+        let krate = self.sema.scope(expr.syntax()).map(|it| it.krate()).unwrap_or_else(|| {
+            hir::Crate::from(
+                *self.sema.db.crate_graph().crates_in_topological_order().last().unwrap(),
+            )
+        });
         let res = code_type
             .autoderef(self.sema.db)
             .enumerate()
             .find(|(_, deref_code_type)| pattern_type == deref_code_type)
             .map(|(count, _)| count)
             .ok_or_else(|| {
+                let display_target = krate.to_display_target(self.sema.db);
+                // Temporary needed to make the borrow checker happy.
                 match_error!(
                     "Pattern type `{}` didn't match code type `{}`",
-                    pattern_type.display(self.sema.db, edition),
-                    code_type.display(self.sema.db, edition)
+                    pattern_type.display(self.sema.db, display_target),
+                    code_type.display(self.sema.db, display_target)
                 )
             });
         res
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 9a3e77f3a93..b00de6ba408 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -7,7 +7,8 @@ use std::{iter, ops::Not};
 
 use either::Either;
 use hir::{
-    db::DefDatabase, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics,
+    db::DefDatabase, DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem,
+    Semantics,
 };
 use ide_db::{
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
@@ -129,10 +130,18 @@ pub(crate) fn hover(
     let file = sema.parse_guess_edition(file_id).syntax().clone();
     let edition =
         sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
+    let display_target = sema.first_crate_or_default(file_id).to_display_target(db);
     let mut res = if range.is_empty() {
-        hover_offset(sema, FilePosition { file_id, offset: range.start() }, file, config, edition)
+        hover_offset(
+            sema,
+            FilePosition { file_id, offset: range.start() },
+            file,
+            config,
+            edition,
+            display_target,
+        )
     } else {
-        hover_ranged(sema, frange, file, config, edition)
+        hover_ranged(sema, frange, file, config, edition, display_target)
     }?;
 
     if let HoverDocFormat::PlainText = config.format {
@@ -148,6 +157,7 @@ fn hover_offset(
     file: SyntaxNode,
     config: &HoverConfig,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<RangeInfo<HoverResult>> {
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT
@@ -169,8 +179,18 @@ fn hover_offset(
     if let Some(doc_comment) = token_as_doc_comment(&original_token) {
         cov_mark::hit!(no_highlight_on_comment_hover);
         return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
-            let res =
-                hover_for_definition(sema, file_id, def, None, &node, None, false, config, edition);
+            let res = hover_for_definition(
+                sema,
+                file_id,
+                def,
+                None,
+                &node,
+                None,
+                false,
+                config,
+                edition,
+                display_target,
+            );
             Some(RangeInfo::new(range, res))
         });
     }
@@ -188,6 +208,7 @@ fn hover_offset(
             false,
             config,
             edition,
+            display_target,
         );
         return Some(RangeInfo::new(range, res));
     }
@@ -277,6 +298,7 @@ fn hover_offset(
                         hovered_definition,
                         config,
                         edition,
+                        display_target,
                     )
                 })
                 .collect::<Vec<_>>(),
@@ -286,12 +308,12 @@ fn hover_offset(
             res.extend(definitions);
             continue;
         }
-        let keywords = || render::keyword(sema, config, &token, edition);
+        let keywords = || render::keyword(sema, config, &token, edition, display_target);
         let underscore = || {
             if !is_same_kind {
                 return None;
             }
-            render::underscore(sema, config, &token, edition)
+            render::underscore(sema, config, &token, edition, display_target)
         };
         let rest_pat = || {
             if !is_same_kind || token.kind() != DOT2 {
@@ -305,7 +327,7 @@ fn hover_offset(
             let record_pat =
                 record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?;
 
-            Some(render::struct_rest_pat(sema, config, &record_pat, edition))
+            Some(render::struct_rest_pat(sema, config, &record_pat, edition, display_target))
         };
         let call = || {
             if !is_same_kind || token.kind() != T!['('] && token.kind() != T![')'] {
@@ -319,17 +341,17 @@ fn hover_offset(
                     _ => return None,
                 }
             };
-            render::type_info_of(sema, config, &Either::Left(call_expr), edition)
+            render::type_info_of(sema, config, &Either::Left(call_expr), edition, display_target)
         };
         let closure = || {
             if !is_same_kind || token.kind() != T![|] {
                 return None;
             }
             let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
-            render::closure_expr(sema, config, c, edition)
+            render::closure_expr(sema, config, c, edition, display_target)
         };
         let literal = || {
-            render::literal(sema, original_token.clone(), edition)
+            render::literal(sema, original_token.clone(), display_target)
                 .map(|markup| HoverResult { markup, actions: vec![] })
         };
         if let Some(result) = keywords()
@@ -362,6 +384,7 @@ fn hover_ranged(
     file: SyntaxNode,
     config: &HoverConfig,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<RangeInfo<HoverResult>> {
     // FIXME: make this work in attributes
     let expr_or_pat = file
@@ -371,16 +394,17 @@ fn hover_ranged(
         .find_map(Either::<ast::Expr, ast::Pat>::cast)?;
     let res = match &expr_or_pat {
         Either::Left(ast::Expr::TryExpr(try_expr)) => {
-            render::try_expr(sema, config, try_expr, edition)
+            render::try_expr(sema, config, try_expr, edition, display_target)
         }
         Either::Left(ast::Expr::PrefixExpr(prefix_expr))
             if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) =>
         {
-            render::deref_expr(sema, config, prefix_expr, edition)
+            render::deref_expr(sema, config, prefix_expr, edition, display_target)
         }
         _ => None,
     };
-    let res = res.or_else(|| render::type_info_of(sema, config, &expr_or_pat, edition));
+    let res =
+        res.or_else(|| render::type_info_of(sema, config, &expr_or_pat, edition, display_target));
     res.map(|it| {
         let range = match expr_or_pat {
             Either::Left(it) => it.syntax().text_range(),
@@ -401,6 +425,7 @@ pub(crate) fn hover_for_definition(
     hovered_definition: bool,
     config: &HoverConfig,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> HoverResult {
     let famous_defs = match &def {
         Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())),
@@ -435,6 +460,7 @@ pub(crate) fn hover_for_definition(
         subst_types.as_ref(),
         config,
         edition,
+        display_target,
     );
     HoverResult {
         markup: render::process_markup(sema.db, def, &markup, config),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index c5a83e58cea..31ef89a07cd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -3,7 +3,7 @@ use std::{env, mem, ops::Not};
 
 use either::Either;
 use hir::{
-    db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DropGlue,
+    db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DisplayTarget, DropGlue,
     DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError,
     MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef,
 };
@@ -38,12 +38,13 @@ pub(super) fn type_info_of(
     _config: &HoverConfig,
     expr_or_pat: &Either<ast::Expr, ast::Pat>,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     let ty_info = match expr_or_pat {
         Either::Left(expr) => sema.type_of_expr(expr)?,
         Either::Right(pat) => sema.type_of_pat(pat)?,
     };
-    type_info(sema, _config, ty_info, edition)
+    type_info(sema, _config, ty_info, edition, display_target)
 }
 
 pub(super) fn closure_expr(
@@ -51,9 +52,10 @@ pub(super) fn closure_expr(
     config: &HoverConfig,
     c: ast::ClosureExpr,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     let TypeInfo { original, .. } = sema.type_of_expr(&c.into())?;
-    closure_ty(sema, config, &TypeInfo { original, adjusted: None }, edition)
+    closure_ty(sema, config, &TypeInfo { original, adjusted: None }, edition, display_target)
 }
 
 pub(super) fn try_expr(
@@ -61,6 +63,7 @@ pub(super) fn try_expr(
     _config: &HoverConfig,
     try_expr: &ast::TryExpr,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original;
     let mut ancestors = try_expr.syntax().ancestors();
@@ -127,8 +130,8 @@ pub(super) fn try_expr(
         res.actions.push(actions);
     }
 
-    let inner_ty = inner_ty.display(sema.db, edition).to_string();
-    let body_ty = body_ty.display(sema.db, edition).to_string();
+    let inner_ty = inner_ty.display(sema.db, display_target).to_string();
+    let body_ty = body_ty.display(sema.db, display_target).to_string();
     let ty_len_max = inner_ty.len().max(body_ty.len());
 
     let l = "Propagated as: ".len() - " Type: ".len();
@@ -153,6 +156,7 @@ pub(super) fn deref_expr(
     _config: &HoverConfig,
     deref_expr: &ast::PrefixExpr,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original;
     let TypeInfo { original, adjusted } =
@@ -170,9 +174,9 @@ pub(super) fn deref_expr(
 
     res.markup = if let Some(adjusted_ty) = adjusted {
         walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
-        let original = original.display(sema.db, edition).to_string();
-        let adjusted = adjusted_ty.display(sema.db, edition).to_string();
-        let inner = inner_ty.display(sema.db, edition).to_string();
+        let original = original.display(sema.db, display_target).to_string();
+        let adjusted = adjusted_ty.display(sema.db, display_target).to_string();
+        let inner = inner_ty.display(sema.db, display_target).to_string();
         let type_len = "To type: ".len();
         let coerced_len = "Coerced to: ".len();
         let deref_len = "Dereferenced from: ".len();
@@ -190,8 +194,8 @@ pub(super) fn deref_expr(
         )
         .into()
     } else {
-        let original = original.display(sema.db, edition).to_string();
-        let inner = inner_ty.display(sema.db, edition).to_string();
+        let original = original.display(sema.db, display_target).to_string();
+        let inner = inner_ty.display(sema.db, display_target).to_string();
         let type_len = "To type: ".len();
         let deref_len = "Dereferenced from: ".len();
         let max_len = (original.len() + type_len).max(inner.len() + deref_len);
@@ -216,6 +220,7 @@ pub(super) fn underscore(
     config: &HoverConfig,
     token: &SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     if token.kind() != T![_] {
         return None;
@@ -224,8 +229,8 @@ pub(super) fn underscore(
     let _it = match_ast! {
         match parent {
             ast::InferType(it) => it,
-            ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it)),edition),
-            ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it)),edition),
+            ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it)),edition, display_target),
+            ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it)),edition, display_target),
             _ => return None,
         }
     };
@@ -259,6 +264,7 @@ pub(super) fn keyword(
     config: &HoverConfig,
     token: &SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     if !token.kind().is_keyword(edition) || !config.documentation || !config.keywords {
         return None;
@@ -267,7 +273,7 @@ pub(super) fn keyword(
     let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate());
 
     let KeywordHint { description, keyword_mod, actions } =
-        keyword_hints(sema, token, parent, edition);
+        keyword_hints(sema, token, parent, edition, display_target);
 
     let doc_owner = find_std_module(&famous_defs, &keyword_mod, edition)?;
     let docs = doc_owner.docs(sema.db)?;
@@ -288,6 +294,7 @@ pub(super) fn struct_rest_pat(
     _config: &HoverConfig,
     pattern: &ast::RecordPat,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> HoverResult {
     let missing_fields = sema.record_pattern_missing_fields(pattern);
 
@@ -309,7 +316,7 @@ pub(super) fn struct_rest_pat(
     res.markup = {
         let mut s = String::from(".., ");
         for (f, _) in &missing_fields {
-            s += f.display(sema.db, edition).to_string().as_ref();
+            s += f.display(sema.db, display_target).to_string().as_ref();
             s += ", ";
         }
         // get rid of trailing comma
@@ -479,41 +486,44 @@ pub(super) fn definition(
     subst_types: Option<&Vec<(Symbol, Type)>>,
     config: &HoverConfig,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Markup {
     let mod_path = definition_path(db, &def, edition);
     let label = match def {
-        Definition::Trait(trait_) => {
-            trait_.display_limited(db, config.max_trait_assoc_items_count, edition).to_string()
-        }
+        Definition::Trait(trait_) => trait_
+            .display_limited(db, config.max_trait_assoc_items_count, display_target)
+            .to_string(),
         Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => {
-            adt.display_limited(db, config.max_fields_count, edition).to_string()
+            adt.display_limited(db, config.max_fields_count, display_target).to_string()
         }
         Definition::Variant(variant) => {
-            variant.display_limited(db, config.max_fields_count, edition).to_string()
+            variant.display_limited(db, config.max_fields_count, display_target).to_string()
         }
         Definition::Adt(adt @ Adt::Enum(_)) => {
-            adt.display_limited(db, config.max_enum_variants_count, edition).to_string()
+            adt.display_limited(db, config.max_enum_variants_count, display_target).to_string()
         }
         Definition::SelfType(impl_def) => {
             let self_ty = &impl_def.self_ty(db);
             match self_ty.as_adt() {
-                Some(adt) => adt.display_limited(db, config.max_fields_count, edition).to_string(),
-                None => self_ty.display(db, edition).to_string(),
+                Some(adt) => {
+                    adt.display_limited(db, config.max_fields_count, display_target).to_string()
+                }
+                None => self_ty.display(db, display_target).to_string(),
             }
         }
         Definition::Macro(it) => {
-            let mut label = it.display(db, edition).to_string();
+            let mut label = it.display(db, display_target).to_string();
             if let Some(macro_arm) = macro_arm {
                 format_to!(label, " // matched arm #{}", macro_arm);
             }
             label
         }
         Definition::Function(fn_) => {
-            fn_.display_with_container_bounds(db, true, edition).to_string()
+            fn_.display_with_container_bounds(db, true, display_target).to_string()
         }
-        _ => def.label(db, edition),
+        _ => def.label(db, display_target),
     };
-    let docs = def.docs(db, famous_defs, edition);
+    let docs = def.docs(db, famous_defs, display_target);
     let value = || match def {
         Definition::Variant(it) => {
             if !it.parent_enum(db).is_data_carrying(db) {
@@ -525,7 +535,10 @@ pub(super) fn definition(
                         let res = it.value(db).map(|it| format!("{it:?}"));
                         if env::var_os("RA_DEV").is_some() {
                             let res = res.as_deref().unwrap_or("");
-                            Some(format!("{res} ({})", render_const_eval_error(db, err, edition)))
+                            Some(format!(
+                                "{res} ({})",
+                                render_const_eval_error(db, err, display_target)
+                            ))
                         } else {
                             res
                         }
@@ -541,9 +554,12 @@ pub(super) fn definition(
                 Ok(it) => match it.render_debug(db) {
                     Ok(it) => it,
                     Err(err) => {
-                        let it = it.render(db, edition);
+                        let it = it.render(db, display_target);
                         if env::var_os("RA_DEV").is_some() {
-                            format!("{it}\n{}", render_const_eval_error(db, err.into(), edition))
+                            format!(
+                                "{it}\n{}",
+                                render_const_eval_error(db, err.into(), display_target)
+                            )
                         } else {
                             it
                         }
@@ -557,7 +573,7 @@ pub(super) fn definition(
                         body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
                     }
                     if env::var_os("RA_DEV").is_some() {
-                        format!("{body}\n{}", render_const_eval_error(db, err, edition))
+                        format!("{body}\n{}", render_const_eval_error(db, err, display_target))
                     } else {
                         body.to_string()
                     }
@@ -570,9 +586,12 @@ pub(super) fn definition(
                 Ok(it) => match it.render_debug(db) {
                     Ok(it) => it,
                     Err(err) => {
-                        let it = it.render(db, edition);
+                        let it = it.render(db, display_target);
                         if env::var_os("RA_DEV").is_some() {
-                            format!("{it}\n{}", render_const_eval_error(db, err.into(), edition))
+                            format!(
+                                "{it}\n{}",
+                                render_const_eval_error(db, err.into(), display_target)
+                            )
                         } else {
                             it
                         }
@@ -586,7 +605,7 @@ pub(super) fn definition(
                         body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
                     }
                     if env::var_os("RA_DEV").is_some() {
-                        format!("{body}\n{}", render_const_eval_error(db, err, edition))
+                        format!("{body}\n{}", render_const_eval_error(db, err, display_target))
                     } else {
                         body.to_string()
                     }
@@ -728,7 +747,9 @@ pub(super) fn definition(
 
     let mut extra = String::new();
     if hovered_definition {
-        if let Some(notable_traits) = render_notable_trait(db, notable_traits, edition) {
+        if let Some(notable_traits) =
+            render_notable_trait(db, notable_traits, edition, display_target)
+        {
             extra.push_str("\n___\n");
             extra.push_str(&notable_traits);
         }
@@ -772,7 +793,7 @@ pub(super) fn definition(
                         .format_with(", ", |(name, ty), fmt| {
                             fmt(&format_args!(
                                 "`{name}` = `{}`",
-                                ty.display_truncated(db, limit, edition)
+                                ty.display_truncated(db, limit, display_target)
                             ))
                         })
                         .to_string()
@@ -799,7 +820,7 @@ struct DropInfo {
 pub(super) fn literal(
     sema: &Semantics<'_, RootDatabase>,
     token: SyntaxToken,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<Markup> {
     let lit = token.parent().and_then(ast::Literal::cast)?;
     let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) {
@@ -847,7 +868,7 @@ pub(super) fn literal(
             _ => return None
         }
     };
-    let ty = ty.display(sema.db, edition);
+    let ty = ty.display(sema.db, display_target);
 
     let mut s = format!("```rust\n{ty}\n```\n___\n\n");
     match value {
@@ -879,6 +900,7 @@ fn render_notable_trait(
     db: &RootDatabase,
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<String> {
     let mut desc = String::new();
     let mut needs_impl_header = true;
@@ -898,7 +920,7 @@ fn render_notable_trait(
                     f(&name.display(db, edition))?;
                     f(&" = ")?;
                     match ty {
-                        Some(ty) => f(&ty.display(db, edition)),
+                        Some(ty) => f(&ty.display(db, display_target)),
                         None => f(&"?"),
                     }
                 })
@@ -914,8 +936,9 @@ fn type_info(
     config: &HoverConfig,
     ty: TypeInfo,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
-    if let Some(res) = closure_ty(sema, config, &ty, edition) {
+    if let Some(res) = closure_ty(sema, config, &ty, edition, display_target) {
         return Some(res);
     };
     let db = sema.db;
@@ -951,7 +974,7 @@ fn type_info(
                             f(&name.display(db, edition))?;
                             f(&" = ")?;
                             match ty {
-                                Some(ty) => f(&ty.display(db, edition)),
+                                Some(ty) => f(&ty.display(db, display_target)),
                                 None => f(&"?"),
                             }
                         })
@@ -965,8 +988,8 @@ fn type_info(
             desc
         };
 
-        let original = original.display(db, edition).to_string();
-        let adjusted = adjusted_ty.display(db, edition).to_string();
+        let original = original.display(db, display_target).to_string();
+        let adjusted = adjusted_ty.display(db, display_target).to_string();
         let static_text_diff_len = "Coerced to: ".len() - "Type: ".len();
         format!(
             "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n{notable}```\n",
@@ -977,8 +1000,10 @@ fn type_info(
         )
         .into()
     } else {
-        let mut desc = format!("```rust\n{}\n```", original.display(db, edition));
-        if let Some(extra) = render_notable_trait(db, &notable_traits(db, &original), edition) {
+        let mut desc = format!("```rust\n{}\n```", original.display(db, display_target));
+        if let Some(extra) =
+            render_notable_trait(db, &notable_traits(db, &original), edition, display_target)
+        {
             desc.push_str("\n___\n");
             desc.push_str(&extra);
         };
@@ -995,6 +1020,7 @@ fn closure_ty(
     config: &HoverConfig,
     TypeInfo { original, adjusted }: &TypeInfo,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<HoverResult> {
     let c = original.as_closure()?;
     let mut captures_rendered = c.captured_items(sema.db)
@@ -1027,12 +1053,14 @@ fn closure_ty(
         walk_and_push_ty(sema.db, adjusted_ty, &mut push_new_def);
         format!(
             "\nCoerced to: {}",
-            adjusted_ty.display(sema.db, edition).with_closure_style(hir::ClosureStyle::ImplFn)
+            adjusted_ty
+                .display(sema.db, display_target)
+                .with_closure_style(hir::ClosureStyle::ImplFn)
         )
     } else {
         String::new()
     };
-    let mut markup = format!("```rust\n{}\n```", c.display_with_impl(sema.db, edition));
+    let mut markup = format!("```rust\n{}\n```", c.display_with_impl(sema.db, display_target));
 
     if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) {
         push_new_def(hir::Trait::from(trait_).into())
@@ -1213,6 +1241,7 @@ fn keyword_hints(
     token: &SyntaxToken,
     parent: syntax::SyntaxNode,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> KeywordHint {
     match token.kind() {
         T![await] | T![loop] | T![match] | T![unsafe] | T![as] | T![try] | T![if] | T![else] => {
@@ -1230,7 +1259,8 @@ fn keyword_hints(
                     walk_and_push_ty(sema.db, &ty.original, &mut push_new_def);
 
                     let ty = ty.adjusted();
-                    let description = format!("{}: {}", token.text(), ty.display(sema.db, edition));
+                    let description =
+                        format!("{}: {}", token.text(), ty.display(sema.db, display_target));
 
                     KeywordHint {
                         description,
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 7c720d97cb6..6b470d921f7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -10947,3 +10947,42 @@ pub struct ManuallyDrop$0<T: ?Sized> {
         "#]],
     );
 }
+
+#[test]
+fn projection_const() {
+    // This uses two crates, which have *no* relation between them, to test another thing:
+    // `render_const_scalar()` used to just use the last crate for the trait env, which will
+    // fail in this scenario.
+    check(
+        r#"
+//- /foo.rs crate:foo
+pub trait PublicFlags {
+    type Internal;
+}
+
+pub struct NoteDialects(<NoteDialects as PublicFlags>::Internal);
+
+impl NoteDialects {
+    pub const CLAP$0: Self = Self(InternalBitFlags);
+}
+
+pub struct InternalBitFlags;
+
+impl PublicFlags for NoteDialects {
+    type Internal = InternalBitFlags;
+}
+//- /bar.rs crate:bar
+    "#,
+        expect![[r#"
+            *CLAP*
+
+            ```rust
+            foo::NoteDialects
+            ```
+
+            ```rust
+            pub const CLAP: Self = NoteDialects(InternalBitFlags)
+            ```
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 63039b1cd34..6babdff52a2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -5,14 +5,14 @@ use std::{
 
 use either::Either;
 use hir::{
-    sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
-    ModuleDefId, Semantics,
+    sym, ClosureStyle, DisplayTarget, HasVisibility, HirDisplay, HirDisplayError, HirWrite,
+    ModuleDef, ModuleDefId, Semantics,
 };
 use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase};
 use ide_db::{text_edit::TextEdit, FxHashSet};
 use itertools::Itertools;
 use smallvec::{smallvec, SmallVec};
-use span::{Edition, EditionedFileId};
+use span::EditionedFileId;
 use stdx::never;
 use syntax::{
     ast::{self, AstNode, HasGenericParams},
@@ -207,7 +207,8 @@ fn hints(
     file_id: EditionedFileId,
     node: SyntaxNode,
 ) {
-    closing_brace::hints(hints, sema, config, file_id, node.clone());
+    let display_target = sema.first_crate_or_default(file_id.file_id()).to_display_target(sema.db);
+    closing_brace::hints(hints, sema, config, file_id, display_target, node.clone());
     if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
         generic_param::hints(hints, famous_defs, config, any_has_generic_args);
     }
@@ -215,8 +216,8 @@ fn hints(
     match_ast! {
         match node {
             ast::Expr(expr) => {
-                chaining::hints(hints, famous_defs, config, file_id, &expr);
-                adjustment::hints(hints, famous_defs, config, file_id, &expr);
+                chaining::hints(hints, famous_defs, config, display_target, &expr);
+                adjustment::hints(hints, famous_defs, config, display_target, &expr);
                 match expr {
                     ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)),
                     ast::Expr::MethodCallExpr(it) => {
@@ -224,7 +225,7 @@ fn hints(
                     }
                     ast::Expr::ClosureExpr(it) => {
                         closure_captures::hints(hints, famous_defs, config, file_id, it.clone());
-                        closure_ret::hints(hints, famous_defs, config, file_id, it)
+                        closure_ret::hints(hints, famous_defs, config, display_target, it)
                     },
                     ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id,  it),
                     _ => Some(()),
@@ -234,7 +235,7 @@ fn hints(
                 binding_mode::hints(hints, famous_defs, config, file_id,  &it);
                 match it {
                     ast::Pat::IdentPat(it) => {
-                        bind_pat::hints(hints, famous_defs, config, file_id, &it);
+                        bind_pat::hints(hints, famous_defs, config, display_target, &it);
                     }
                     ast::Pat::RangePat(it) => {
                         range_exclusive::hints(hints, famous_defs, config, file_id, it);
@@ -704,7 +705,7 @@ fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     ty: &hir::Type,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<InlayHintLabel> {
     fn rec(
         sema: &Semantics<'_, RootDatabase>,
@@ -713,7 +714,7 @@ fn label_of_ty(
         ty: &hir::Type,
         label_builder: &mut InlayHintLabelBuilder<'_>,
         config: &InlayHintsConfig,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) -> Result<(), HirDisplayError> {
         let iter_item_type = hint_iterator(sema, famous_defs, ty);
         match iter_item_type {
@@ -744,12 +745,12 @@ fn label_of_ty(
                 label_builder.write_str(LABEL_ITEM)?;
                 label_builder.end_location_link();
                 label_builder.write_str(LABEL_MIDDLE2)?;
-                rec(sema, famous_defs, max_length, &ty, label_builder, config, edition)?;
+                rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?;
                 label_builder.write_str(LABEL_END)?;
                 Ok(())
             }
             None => ty
-                .display_truncated(sema.db, max_length, edition)
+                .display_truncated(sema.db, max_length, display_target)
                 .with_closure_style(config.closure_style)
                 .write_to(label_builder),
         }
@@ -762,7 +763,8 @@ fn label_of_ty(
         result: InlayHintLabel::default(),
         resolve: config.fields_to_resolve.resolve_label_location,
     };
-    let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition);
+    let _ =
+        rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, display_target);
     let r = label_builder.finish();
     Some(r)
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 8522ef0a6d5..91b81872952 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -7,12 +7,12 @@ use std::ops::Not;
 
 use either::Either;
 use hir::{
-    Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
+    Adjust, Adjustment, AutoBorrow, DisplayTarget, HirDisplay, Mutability, OverloadedDeref,
+    PointerCast, Safety,
 };
 use ide_db::famous_defs::FamousDefs;
 
 use ide_db::text_edit::TextEditBuilder;
-use span::EditionedFileId;
 use syntax::ast::{self, prec::ExprPrecedence, AstNode};
 
 use crate::{
@@ -24,7 +24,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
+    display_target: DisplayTarget,
     expr: &ast::Expr,
 ) -> Option<()> {
     if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) {
@@ -163,8 +163,8 @@ pub(super) fn hints(
             tooltip: Some(config.lazy_tooltip(|| {
                 InlayTooltip::Markdown(format!(
                     "`{}` → `{}` ({coercion} coercion)",
-                    source.display(sema.db, file_id.edition()),
-                    target.display(sema.db, file_id.edition()),
+                    source.display(sema.db, display_target),
+                    target.display(sema.db, display_target),
                 ))
             })),
         };
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index c2986a9aa66..4379153acaa 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -3,11 +3,10 @@
 //! fn f(a: i32, b: i32) -> i32 { a + b }
 //! let _x /* i32 */= f(4, 4);
 //! ```
-use hir::Semantics;
+use hir::{DisplayTarget, Semantics};
 use ide_db::{famous_defs::FamousDefs, RootDatabase};
 
 use itertools::Itertools;
-use span::EditionedFileId;
 use syntax::{
     ast::{self, AstNode, HasGenericArgs, HasName},
     match_ast,
@@ -22,7 +21,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
+    display_target: DisplayTarget,
     pat: &ast::IdentPat,
 ) -> Option<()> {
     if !config.type_hints {
@@ -70,7 +69,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?;
+    let mut label = label_of_ty(famous_defs, config, &ty, display_target)?;
 
     if config.hide_named_constructor_hints
         && is_named_constructor(sema, pat, &label.to_string()).is_some()
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 8471547727f..604719bc366 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -1,6 +1,6 @@
 //! Implementation of "chaining" inlay hints.
+use hir::DisplayTarget;
 use ide_db::famous_defs::FamousDefs;
-use span::EditionedFileId;
 use syntax::{
     ast::{self, AstNode},
     Direction, NodeOrToken, SyntaxKind, T,
@@ -14,7 +14,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
+    display_target: DisplayTarget,
     expr: &ast::Expr,
 ) -> Option<()> {
     if !config.chaining_hints {
@@ -58,7 +58,7 @@ pub(super) fn hints(
                     }
                 }
             }
-            let label = label_of_ty(famous_defs, config, &ty, file_id.edition())?;
+            let label = label_of_ty(famous_defs, config, &ty, display_target)?;
             acc.push(InlayHint {
                 range: expr.syntax().text_range(),
                 kind: InlayKind::Chaining,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 3767d34e2c7..bec6d38ee9c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -3,7 +3,7 @@
 //! fn g() {
 //! } /* fn g */
 //! ```
-use hir::{HirDisplay, Semantics};
+use hir::{DisplayTarget, HirDisplay, Semantics};
 use ide_db::{FileRange, RootDatabase};
 use span::EditionedFileId;
 use syntax::{
@@ -21,6 +21,7 @@ pub(super) fn hints(
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
     file_id: EditionedFileId,
+    display_target: DisplayTarget,
     original_node: SyntaxNode,
 ) -> Option<()> {
     let min_lines = config.closing_brace_hints_min_lines?;
@@ -43,9 +44,9 @@ pub(super) fn hints(
                         Some(tr) => format!(
                             "impl {} for {}",
                             tr.name(sema.db).display(sema.db, file_id.edition()),
-                            ty.display_truncated(sema.db, config.max_length, file_id.edition(),
+                            ty.display_truncated(sema.db, config.max_length, display_target,
                         )),
-                        None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, file_id.edition())),
+                        None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, display_target)),
                     };
                     (hint_text, None)
                 },
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
index 7858b1d90a3..61c9c25fe73 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
@@ -1,8 +1,8 @@
 //! Implementation of "closure return type" inlay hints.
 //!
 //! Tests live in [`bind_pat`][super::bind_pat] module.
+use hir::DisplayTarget;
 use ide_db::famous_defs::FamousDefs;
-use span::EditionedFileId;
 use syntax::ast::{self, AstNode};
 
 use crate::{
@@ -14,7 +14,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
+    display_target: DisplayTarget,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
     if config.closure_return_type_hints == ClosureReturnTypeHints::Never {
@@ -43,7 +43,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?;
+    let mut label = label_of_ty(famous_defs, config, &ty, display_target)?;
 
     if arrow.is_none() {
         label.prepend_str(" -> ");
diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret.rs b/src/tools/rust-analyzer/crates/ide/src/interpret.rs
index ae11072e34b..74dad488b4d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/interpret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/interpret.rs
@@ -1,6 +1,5 @@
-use hir::{ConstEvalError, DefWithBody, Semantics};
+use hir::{ConstEvalError, DefWithBody, DisplayTarget, Semantics};
 use ide_db::{base_db::SourceRootDatabase, FilePosition, LineIndexDatabase, RootDatabase};
-use span::Edition;
 use std::time::{Duration, Instant};
 use stdx::format_to;
 use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange};
@@ -46,15 +45,15 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura
             None => format!("file://{path} range {text_range:?}"),
         }
     };
-    let edition = def.module(db).krate().edition(db);
+    let display_target = def.module(db).krate().to_display_target(db);
     let start_time = Instant::now();
     let res = match def {
         DefWithBody::Function(it) => it.eval(db, span_formatter),
-        DefWithBody::Static(it) => it.eval(db).map(|it| it.render(db, edition)),
-        DefWithBody::Const(it) => it.eval(db).map(|it| it.render(db, edition)),
+        DefWithBody::Static(it) => it.eval(db).map(|it| it.render(db, display_target)),
+        DefWithBody::Const(it) => it.eval(db).map(|it| it.render(db, display_target)),
         _ => unreachable!(),
     };
-    let res = res.unwrap_or_else(|e| render_const_eval_error(db, e, edition));
+    let res = res.unwrap_or_else(|e| render_const_eval_error(db, e, display_target));
     let duration = Instant::now() - start_time;
     Some((duration, res))
 }
@@ -62,7 +61,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura
 pub(crate) fn render_const_eval_error(
     db: &RootDatabase,
     e: ConstEvalError,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> String {
     let span_formatter = |file_id, text_range: TextRange| {
         let path = &db
@@ -76,6 +75,6 @@ pub(crate) fn render_const_eval_error(
         }
     };
     let mut r = String::new();
-    _ = e.pretty_print(&mut r, db, span_formatter, edition);
+    _ = e.pretty_print(&mut r, db, span_formatter, display_target);
     r
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 25d12a4c0b4..5754b4fa82f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -11,7 +11,6 @@ use ide_db::{
     FilePosition, RootDatabase,
 };
 use itertools::Itertools;
-use span::Edition;
 use syntax::{AstNode, SyntaxKind::*, T};
 
 use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo};
@@ -305,13 +304,13 @@ fn def_to_non_local_moniker(
                 if let Some(trait_ref) = impl_.trait_ref(db) {
                     // Trait impls use the trait type for the 2nd parameter.
                     reverse_description.push(MonikerDescriptor {
-                        name: display(db, edition, module, trait_ref),
+                        name: display(db, module, trait_ref),
                         desc: MonikerDescriptorKind::TypeParameter,
                     });
                 }
                 // Both inherent and trait impls use the self type for the first parameter.
                 reverse_description.push(MonikerDescriptor {
-                    name: display(db, edition, module, impl_.self_ty(db)),
+                    name: display(db, module, impl_.self_ty(db)),
                     desc: MonikerDescriptorKind::TypeParameter,
                 });
                 reverse_description.push(MonikerDescriptor {
@@ -390,17 +389,12 @@ fn def_to_non_local_moniker(
     })
 }
 
-fn display<T: HirDisplay>(
-    db: &RootDatabase,
-    edition: Edition,
-    module: hir::Module,
-    it: T,
-) -> String {
+fn display<T: HirDisplay>(db: &RootDatabase, module: hir::Module, it: T) -> String {
     match it.display_source_code(db, module.into(), true) {
         Ok(result) => result,
         // Fallback on display variant that always succeeds
         Err(_) => {
-            let fallback_result = it.display(db, edition).to_string();
+            let fallback_result = it.display(db, module.krate().to_display_target(db)).to_string();
             tracing::error!(
                 display = %fallback_result, "`display_source_code` failed; falling back to using display"
             );
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index d9f80cb53dd..d67aaac06fb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -6,7 +6,7 @@ use arrayvec::ArrayVec;
 use either::Either;
 use hir::{
     db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasCrate,
-    HasSource, HirDisplay, HirFileId, HirFileIdExt, InFile, LocalSource, ModuleSource,
+    HasSource, HirDisplay, HirFileId, InFile, LocalSource, ModuleSource,
 };
 use ide_db::{
     defs::Definition,
@@ -116,7 +116,9 @@ impl NavigationTarget {
                             SymbolKind::Module,
                         );
                         res.docs = module.docs(db);
-                        res.description = Some(module.display(db, edition).to_string());
+                        res.description = Some(
+                            module.display(db, module.krate().to_display_target(db)).to_string(),
+                        );
                         res
                     },
                 )
@@ -183,6 +185,7 @@ impl TryToNav for FileSymbol {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let edition =
             self.def.module(db).map(|it| it.krate().edition(db)).unwrap_or(Edition::CURRENT);
+        let display_target = self.def.krate(db).to_display_target(db);
         Some(
             orig_range_with_focus_r(
                 db,
@@ -203,16 +206,34 @@ impl TryToNav for FileSymbol {
                     focus_range,
                     container_name: self.container_name.clone(),
                     description: match self.def {
-                        hir::ModuleDef::Module(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Function(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Adt(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Variant(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Const(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Static(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Trait(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::TraitAlias(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::TypeAlias(it) => Some(it.display(db, edition).to_string()),
-                        hir::ModuleDef::Macro(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Module(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::Function(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::Adt(it) => Some(it.display(db, display_target).to_string()),
+                        hir::ModuleDef::Variant(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::Const(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::Static(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::Trait(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::TraitAlias(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::TypeAlias(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
+                        hir::ModuleDef::Macro(it) => {
+                            Some(it.display(db, display_target).to_string())
+                        }
                         hir::ModuleDef::BuiltinType(_) => None,
                     },
                     docs: None,
@@ -353,12 +374,11 @@ impl ToNavFromAst for hir::TraitAlias {
 
 impl<D> TryToNav for D
 where
-    D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay,
+    D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay + HasCrate,
     D::Ast: ast::HasName,
 {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let src = self.source(db)?;
-        let edition = src.file_id.original_file(db).edition();
         Some(
             NavigationTarget::from_named(
                 db,
@@ -367,7 +387,8 @@ where
             )
             .map(|mut res| {
                 res.docs = self.docs(db);
-                res.description = Some(self.display(db, edition).to_string());
+                res.description =
+                    Some(self.display(db, self.krate(db).to_display_target(db)).to_string());
                 res.container_name = self.container_name(db);
                 res
             }),
@@ -439,7 +460,8 @@ impl TryToNav for hir::ExternCrateDecl {
         let focus = value
             .rename()
             .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right));
-        let edition = self.module(db).krate().edition(db);
+        let krate = self.module(db).krate();
+        let edition = krate.edition(db);
 
         Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map(
             |(FileRange { file_id, range: full_range }, focus_range)| {
@@ -455,7 +477,7 @@ impl TryToNav for hir::ExternCrateDecl {
                 );
 
                 res.docs = self.docs(db);
-                res.description = Some(self.display(db, edition).to_string());
+                res.description = Some(self.display(db, krate.to_display_target(db)).to_string());
                 res.container_name = container_name(db, *self, edition);
                 res
             },
@@ -466,14 +488,15 @@ impl TryToNav for hir::ExternCrateDecl {
 impl TryToNav for hir::Field {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let src = self.source(db)?;
-        let edition = self.parent_def(db).module(db).krate().edition(db);
+        let krate = self.parent_def(db).module(db).krate();
 
         let field_source = match &src.value {
             FieldSource::Named(it) => {
                 NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map(
                     |mut res| {
                         res.docs = self.docs(db);
-                        res.description = Some(self.display(db, edition).to_string());
+                        res.description =
+                            Some(self.display(db, krate.to_display_target(db)).to_string());
                         res
                     },
                 )
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index 3e8295e3f08..d0e1c2097a7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -446,6 +446,7 @@ mod tests {
     use expect_test::{expect, Expect};
     use ide_db::source_change::SourceChange;
     use ide_db::text_edit::TextEdit;
+    use itertools::Itertools;
     use stdx::trim_indent;
     use test_utils::assert_eq_text;
 
@@ -496,6 +497,31 @@ mod tests {
         };
     }
 
+    #[track_caller]
+    fn check_conflicts(new_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        let (analysis, position, conflicts) = fixture::annotations(ra_fixture);
+        let source_change = analysis.rename(position, new_name).unwrap().unwrap();
+        let expected_conflicts = conflicts
+            .into_iter()
+            .map(|(file_range, _)| (file_range.file_id, file_range.range))
+            .sorted_unstable_by_key(|(file_id, range)| (*file_id, range.start()))
+            .collect_vec();
+        let found_conflicts = source_change
+            .source_file_edits
+            .iter()
+            .flat_map(|(file_id, (edit, _))| {
+                edit.into_iter()
+                    .filter(|edit| edit.annotation.is_some())
+                    .map(move |edit| (*file_id, edit.delete))
+            })
+            .sorted_unstable_by_key(|(file_id, range)| (*file_id, range.start()))
+            .collect_vec();
+        assert_eq!(
+            expected_conflicts, found_conflicts,
+            "rename conflicts mismatch: {source_change:#?}"
+        );
+    }
+
     fn check_expect(
         new_name: &str,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
@@ -548,6 +574,37 @@ mod tests {
     }
 
     #[test]
+    fn rename_will_shadow() {
+        check_conflicts(
+            "new_name",
+            r#"
+fn foo() {
+    let mut new_name = 123;
+    let old_name$0 = 456;
+     // ^^^^^^^^
+    new_name = 789 + new_name;
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn rename_will_be_shadowed() {
+        check_conflicts(
+            "new_name",
+            r#"
+fn foo() {
+    let mut old_name$0 = 456;
+         // ^^^^^^^^
+    let new_name = 123;
+    old_name = 789 + old_name;
+ // ^^^^^^^^         ^^^^^^^^
+}
+        "#,
+        );
+    }
+
+    #[test]
     fn test_prepare_rename_namelikes() {
         check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
         check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"9..17: lifetime"#]]);
@@ -1024,6 +1081,7 @@ mod foo$0;
                             Indel {
                                 insert: "foo2",
                                 delete: 4..7,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1071,6 +1129,7 @@ use crate::foo$0::FooContent;
                             Indel {
                                 insert: "quux",
                                 delete: 8..11,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1082,6 +1141,7 @@ use crate::foo$0::FooContent;
                             Indel {
                                 insert: "quux",
                                 delete: 11..14,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1123,6 +1183,7 @@ mod fo$0o;
                             Indel {
                                 insert: "foo2",
                                 delete: 4..7,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1171,6 +1232,7 @@ mod outer { mod fo$0o; }
                             Indel {
                                 insert: "bar",
                                 delete: 16..19,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1242,6 +1304,7 @@ pub mod foo$0;
                             Indel {
                                 insert: "foo2",
                                 delete: 27..30,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1253,6 +1316,7 @@ pub mod foo$0;
                             Indel {
                                 insert: "foo2",
                                 delete: 8..11,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1308,6 +1372,7 @@ mod quux;
                             Indel {
                                 insert: "foo2",
                                 delete: 4..7,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1441,10 +1506,12 @@ pub fn baz() {}
                             Indel {
                                 insert: "r#fn",
                                 delete: 4..7,
+                                annotation: None,
                             },
                             Indel {
                                 insert: "r#fn",
                                 delete: 22..25,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1509,10 +1576,12 @@ pub fn baz() {}
                             Indel {
                                 insert: "foo",
                                 delete: 4..8,
+                                annotation: None,
                             },
                             Indel {
                                 insert: "foo",
                                 delete: 23..27,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1574,6 +1643,7 @@ fn bar() {
                             Indel {
                                 insert: "dyn",
                                 delete: 7..10,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1585,6 +1655,7 @@ fn bar() {
                             Indel {
                                 insert: "r#dyn",
                                 delete: 18..21,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1614,6 +1685,7 @@ fn bar() {
                             Indel {
                                 insert: "r#dyn",
                                 delete: 7..10,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1625,6 +1697,7 @@ fn bar() {
                             Indel {
                                 insert: "dyn",
                                 delete: 18..21,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1654,6 +1727,7 @@ fn bar() {
                             Indel {
                                 insert: "r#dyn",
                                 delete: 7..10,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1665,6 +1739,7 @@ fn bar() {
                             Indel {
                                 insert: "dyn",
                                 delete: 18..21,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1701,10 +1776,12 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 7..10,
+                                annotation: None,
                             },
                             Indel {
                                 insert: "abc",
                                 delete: 32..35,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1716,6 +1793,7 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 18..23,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1749,10 +1827,12 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 7..12,
+                                annotation: None,
                             },
                             Indel {
                                 insert: "abc",
                                 delete: 34..39,
+                                annotation: None,
                             },
                         ],
                     ),
@@ -1764,6 +1844,7 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 18..21,
+                                annotation: None,
                             },
                         ],
                     ),
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 509ae3204c3..b8deed01fb7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -9,6 +9,7 @@ use hir::{
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
 use ide_db::{
+    base_db::SourceDatabase,
     defs::Definition,
     documentation::docs_from_attrs,
     helpers::visit_file_defs,
@@ -399,7 +400,8 @@ pub(crate) fn runnable_impl(
     sema: &Semantics<'_, RootDatabase>,
     def: &hir::Impl,
 ) -> Option<Runnable> {
-    let edition = def.module(sema.db).krate().edition(sema.db);
+    let display_target = def.module(sema.db).krate().to_display_target(sema.db);
+    let edition = display_target.edition;
     let attrs = def.attrs(sema.db);
     if !has_runnable_doc_test(&attrs) {
         return None;
@@ -408,7 +410,7 @@ pub(crate) fn runnable_impl(
     let nav = def.try_to_nav(sema.db)?.call_site();
     let ty = def.self_ty(sema.db);
     let adt_name = ty.as_adt()?.name(sema.db);
-    let mut ty_args = ty.generic_parameters(sema.db, edition).peekable();
+    let mut ty_args = ty.generic_parameters(sema.db, display_target).peekable();
     let params = if ty_args.peek().is_some() {
         format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty)))
     } else {
@@ -494,7 +496,11 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
         Definition::SelfType(it) => it.attrs(db),
         _ => return None,
     };
-    let edition = def.krate(db).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
+    let krate = def.krate(db);
+    let edition = krate.map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
+    let display_target = krate
+        .unwrap_or_else(|| (*db.crate_graph().crates_in_topological_order().last().unwrap()).into())
+        .to_display_target(db);
     if !has_runnable_doc_test(&attrs) {
         return None;
     }
@@ -509,7 +515,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
             if let Some(ty) = assoc_item.implementing_ty(db) {
                 if let Some(adt) = ty.as_adt() {
                     let name = adt.name(db);
-                    let mut ty_args = ty.generic_parameters(db, edition).peekable();
+                    let mut ty_args = ty.generic_parameters(db, display_target).peekable();
                     format_to!(path, "{}", name.display(db, edition));
                     if ty_args.peek().is_some() {
                         format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty)));
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index f9972116004..b5468a5aee9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -4,7 +4,9 @@
 use std::collections::BTreeSet;
 
 use either::Either;
-use hir::{AssocItem, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait};
+use hir::{
+    AssocItem, DisplayTarget, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait,
+};
 use ide_db::{
     active_parameter::{callable_for_node, generic_def_for_node},
     documentation::{Documentation, HasDocs},
@@ -82,6 +84,7 @@ pub(crate) fn signature_help(
     let token = sema.descend_into_macros_single_exact(token);
     let edition =
         sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
+    let display_target = sema.first_crate_or_default(file_id).to_display_target(db);
 
     for node in token.parent_ancestors() {
         match_ast! {
@@ -91,49 +94,49 @@ pub(crate) fn signature_help(
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_call(&sema, arg_list, token, edition);
+                    return signature_help_for_call(&sema, arg_list, token, edition, display_target);
                 },
                 ast::GenericArgList(garg_list) => {
                     let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_generics(&sema, garg_list, token, edition);
+                    return signature_help_for_generics(&sema, garg_list, token, edition, display_target);
                 },
                 ast::RecordExpr(record) => {
                     let cursor_outside = record.record_expr_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_record_lit(&sema, record, token, edition);
+                    return signature_help_for_record_lit(&sema, record, token, edition, display_target);
                 },
                 ast::RecordPat(record) => {
                     let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_record_pat(&sema, record, token, edition);
+                    return signature_help_for_record_pat(&sema, record, token, edition, display_target);
                 },
                 ast::TupleStructPat(tuple_pat) => {
                     let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition);
+                    return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition, display_target);
                 },
                 ast::TuplePat(tuple_pat) => {
                     let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_tuple_pat(&sema, tuple_pat, token, edition);
+                    return signature_help_for_tuple_pat(&sema, tuple_pat, token, display_target);
                 },
                 ast::TupleExpr(tuple_expr) => {
                     let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_tuple_expr(&sema, tuple_expr, token, edition);
+                    return signature_help_for_tuple_expr(&sema, tuple_expr, token, display_target);
                 },
                 _ => (),
             }
@@ -158,6 +161,7 @@ fn signature_help_for_call(
     arg_list: ast::ArgList,
     token: SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     // Find the calling expression and its NameRef
     let mut nodes = arg_list.syntax().ancestors().skip(1);
@@ -221,7 +225,7 @@ fn signature_help_for_call(
     res.signature.push('(');
     {
         if let Some((self_param, _)) = callable.receiver_param(db) {
-            format_to!(res.signature, "{}", self_param.display(db, edition))
+            format_to!(res.signature, "{}", self_param.display(db, display_target))
         }
         let mut buf = String::new();
         for (idx, p) in callable.params().into_iter().enumerate() {
@@ -242,9 +246,9 @@ fn signature_help_for_call(
             // (see FIXME in tests::impl_trait) and falling back on any unknowns.
             match (p.ty().contains_unknown(), fn_params.as_deref()) {
                 (true, Some(fn_params)) => {
-                    format_to!(buf, "{}", fn_params[idx].ty().display(db, edition))
+                    format_to!(buf, "{}", fn_params[idx].ty().display(db, display_target))
                 }
-                _ => format_to!(buf, "{}", p.ty().display(db, edition)),
+                _ => format_to!(buf, "{}", p.ty().display(db, display_target)),
             }
             res.push_call_param(&buf);
         }
@@ -253,7 +257,7 @@ fn signature_help_for_call(
 
     let mut render = |ret_type: hir::Type| {
         if !ret_type.is_unit() {
-            format_to!(res.signature, " -> {}", ret_type.display(db, edition));
+            format_to!(res.signature, " -> {}", ret_type.display(db, display_target));
         }
     };
     match callable.kind() {
@@ -274,6 +278,7 @@ fn signature_help_for_generics(
     arg_list: ast::GenericArgList,
     token: SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) =
         generic_def_for_node(sema, &arg_list, &token)?;
@@ -345,7 +350,7 @@ fn signature_help_for_generics(
         }
 
         buf.clear();
-        format_to!(buf, "{}", param.display(db, edition));
+        format_to!(buf, "{}", param.display(db, display_target));
         res.push_generic_param(&buf);
     }
     if let hir::GenericDef::Trait(tr) = generics_def {
@@ -400,6 +405,7 @@ fn signature_help_for_record_lit(
     record: ast::RecordExpr,
     token: SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     signature_help_for_record_(
         sema,
@@ -412,6 +418,7 @@ fn signature_help_for_record_lit(
             .map(|(field, _, ty)| (field, ty)),
         token,
         edition,
+        display_target,
     )
 }
 
@@ -420,6 +427,7 @@ fn signature_help_for_record_pat(
     record: ast::RecordPat,
     token: SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     signature_help_for_record_(
         sema,
@@ -431,6 +439,7 @@ fn signature_help_for_record_pat(
             .filter_map(|field| sema.resolve_record_pat_field(&field)),
         token,
         edition,
+        display_target,
     )
 }
 
@@ -439,6 +448,7 @@ fn signature_help_for_tuple_struct_pat(
     pat: ast::TupleStructPat,
     token: SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     let path = pat.path()?;
     let path_res = sema.resolve_path(&path)?;
@@ -484,7 +494,7 @@ fn signature_help_for_tuple_struct_pat(
         token,
         pat.fields(),
         fields.into_iter().map(|it| it.ty(db)),
-        edition,
+        display_target,
     ))
 }
 
@@ -492,7 +502,7 @@ fn signature_help_for_tuple_pat(
     sema: &Semantics<'_, RootDatabase>,
     pat: ast::TuplePat,
     token: SyntaxToken,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     let db = sema.db;
     let field_pats = pat.fields();
@@ -512,7 +522,7 @@ fn signature_help_for_tuple_pat(
         token,
         field_pats,
         fields.into_iter(),
-        edition,
+        display_target,
     ))
 }
 
@@ -520,7 +530,7 @@ fn signature_help_for_tuple_expr(
     sema: &Semantics<'_, RootDatabase>,
     expr: ast::TupleExpr,
     token: SyntaxToken,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     let active_parameter = Some(
         expr.syntax()
@@ -542,7 +552,7 @@ fn signature_help_for_tuple_expr(
     let fields = expr.original.tuple_fields(db);
     let mut buf = String::new();
     for ty in fields {
-        format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition));
+        format_to!(buf, "{}", ty.display_truncated(db, Some(20), display_target));
         res.push_call_param(&buf);
         buf.clear();
     }
@@ -557,6 +567,7 @@ fn signature_help_for_record_(
     fields2: impl Iterator<Item = (hir::Field, hir::Type)>,
     token: SyntaxToken,
     edition: Edition,
+    display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
     let active_parameter = field_list_children
         .filter_map(NodeOrToken::into_token)
@@ -617,7 +628,7 @@ fn signature_help_for_record_(
             buf,
             "{}: {}",
             name.display(db, edition),
-            ty.display_truncated(db, Some(20), edition)
+            ty.display_truncated(db, Some(20), display_target)
         );
         res.push_record_field(&buf);
         buf.clear();
@@ -632,7 +643,7 @@ fn signature_help_for_record_(
             buf,
             "{}: {}",
             name.display(db, edition),
-            field.ty(db).display_truncated(db, Some(20), edition)
+            field.ty(db).display_truncated(db, Some(20), display_target)
         );
         res.push_record_field(&buf);
         buf.clear();
@@ -648,7 +659,7 @@ fn signature_help_for_tuple_pat_ish(
     token: SyntaxToken,
     mut field_pats: AstChildren<ast::Pat>,
     fields: impl ExactSizeIterator<Item = hir::Type>,
-    edition: Edition,
+    display_target: DisplayTarget,
 ) -> SignatureHelp {
     let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));
     let is_left_of_rest_pat =
@@ -675,7 +686,7 @@ fn signature_help_for_tuple_pat_ish(
 
     let mut buf = String::new();
     for ty in fields {
-        format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition));
+        format_to!(buf, "{}", ty.display_truncated(db, Some(20), display_target));
         res.push_call_param(&buf);
         buf.clear();
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
index 77a011cac19..90e350949b8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
@@ -139,6 +139,7 @@ mod tests {
                                         Indel {
                                             insert: "3",
                                             delete: 33..34,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -147,6 +148,8 @@ mod tests {
                         },
                         file_system_edits: [],
                         is_snippet: false,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: None,
@@ -179,6 +182,7 @@ mod tests {
                                         Indel {
                                             insert: "3",
                                             delete: 33..34,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -192,6 +196,7 @@ mod tests {
                                         Indel {
                                             insert: "3",
                                             delete: 11..12,
+                                            annotation: None,
                                         },
                                     ],
                                 },
@@ -200,6 +205,8 @@ mod tests {
                         },
                         file_system_edits: [],
                         is_snippet: false,
+                        annotations: {},
+                        next_annotation_id: 0,
                     },
                 ),
                 command: None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 41957bad7e0..332aecf1e3c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -3,7 +3,7 @@
 
 use hir::{db::HirDatabase, Crate, HirFileIdExt, Module, Semantics};
 use ide_db::{
-    base_db::{SourceRootDatabase, VfsPath},
+    base_db::{SourceDatabase, SourceRootDatabase, VfsPath},
     defs::Definition,
     documentation::Documentation,
     famous_defs::FamousDefs,
@@ -118,7 +118,11 @@ fn documentation_for_definition(
     def.docs(
         sema.db,
         famous_defs.as_ref(),
-        def.krate(sema.db).map(|it| it.edition(sema.db)).unwrap_or(Edition::CURRENT),
+        def.krate(sema.db)
+            .unwrap_or_else(|| {
+                (*sema.db.crate_graph().crates_in_topological_order().last().unwrap()).into()
+            })
+            .to_display_target(sema.db),
     )
 }
 
@@ -173,6 +177,7 @@ impl StaticIndex<'_> {
         let root = sema.parse_guess_edition(file_id).syntax().clone();
         let edition =
             sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
+        let display_target = sema.first_crate_or_default(file_id).to_display_target(self.db);
         let tokens = root.descendants_with_tokens().filter_map(|it| match it {
             syntax::NodeOrToken::Node(_) => None,
             syntax::NodeOrToken::Token(it) => Some(it),
@@ -213,6 +218,7 @@ impl StaticIndex<'_> {
                         false,
                         &hover_config,
                         edition,
+                        display_target,
                     )),
                     definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
                         FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
@@ -222,7 +228,7 @@ impl StaticIndex<'_> {
                     display_name: def
                         .name(self.db)
                         .map(|name| name.display(self.db, edition).to_string()),
-                    signature: Some(def.label(self.db, edition)),
+                    signature: Some(def.label(self.db, display_target)),
                     kind: def_to_kind(self.db, def),
                 });
                 self.def_map.insert(def, it);
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index f8ecaa8fdf2..a44be67668c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -268,8 +268,7 @@ struct AttrsStats {
 
 impl fmt::Display for AttrsStats {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let size =
-            self.entries * std::mem::size_of::<Attrs>() + self.total * std::mem::size_of::<Attr>();
+        let size = self.entries * size_of::<Attrs>() + self.total * size_of::<Attr>();
         let size = Bytes::new(size as _);
         write!(
             fmt,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 519133e3ad1..83082496d5b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -14,8 +14,11 @@ mod tests;
 
 use std::ops::ControlFlow;
 
-use hir::{HirFileIdExt, InFile, InRealFile, MacroFileIdExt, MacroKind, Name, Semantics};
-use ide_db::{FxHashMap, Ranker, RootDatabase, SymbolKind};
+use either::Either;
+use hir::{
+    DefWithBody, HirFileIdExt, InFile, InRealFile, MacroFileIdExt, MacroKind, Name, Semantics,
+};
+use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind};
 use span::EditionedFileId;
 use syntax::{
     ast::{self, IsString},
@@ -232,7 +235,6 @@ fn traverse(
     range_to_highlight: TextRange,
 ) {
     let is_unlinked = sema.file_to_module_def(file_id).is_none();
-    let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
 
     enum AttrOrDerive {
         Attr(ast::Item),
@@ -247,13 +249,22 @@ fn traverse(
         }
     }
 
+    let empty = FxHashSet::default();
+
+    // FIXME: accommodate range highlighting
     let mut tt_level = 0;
+    // FIXME: accommodate range highlighting
     let mut attr_or_derive_item = None;
 
     // FIXME: these are not perfectly accurate, we determine them by the real file's syntax tree
     // an attribute nested in a macro call will not emit `inside_attribute`
     let mut inside_attribute = false;
 
+    // FIXME: accommodate range highlighting
+    let mut body_stack: Vec<Option<DefWithBody>> = vec![];
+    let mut per_body_cache: FxHashMap<DefWithBody, (FxHashSet<_>, FxHashMap<Name, u32>)> =
+        FxHashMap::default();
+
     // Walk all nodes, keeping track of whether we are inside a macro or not.
     // If in macro, expand it first and highlight the expanded code.
     let mut preorder = root.preorder_with_tokens();
@@ -282,48 +293,68 @@ fn traverse(
             Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
                 inside_attribute = false
             }
-
             Enter(NodeOrToken::Node(node)) => {
-                if let Some(item) = ast::Item::cast(node.clone()) {
+                if let Some(item) = <Either<ast::Item, ast::Variant>>::cast(node.clone()) {
                     match item {
-                        ast::Item::Fn(_) | ast::Item::Const(_) | ast::Item::Static(_) => {
-                            bindings_shadow_count.clear()
-                        }
-                        _ => (),
-                    }
-
-                    if attr_or_derive_item.is_none() {
-                        if sema.is_attr_macro_call(InFile::new(file_id.into(), &item)) {
-                            attr_or_derive_item = Some(AttrOrDerive::Attr(item));
-                        } else {
-                            let adt = match item {
-                                ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
-                                ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
-                                ast::Item::Union(it) => Some(ast::Adt::Union(it)),
-                                _ => None,
-                            };
-                            match adt {
-                                Some(adt)
-                                    if sema
-                                        .is_derive_annotated(InFile::new(file_id.into(), &adt)) =>
-                                {
-                                    attr_or_derive_item =
-                                        Some(AttrOrDerive::Derive(ast::Item::from(adt)));
+                        Either::Left(item) => {
+                            match &item {
+                                ast::Item::Fn(it) => {
+                                    body_stack.push(sema.to_def(it).map(Into::into))
+                                }
+                                ast::Item::Const(it) => {
+                                    body_stack.push(sema.to_def(it).map(Into::into))
+                                }
+                                ast::Item::Static(it) => {
+                                    body_stack.push(sema.to_def(it).map(Into::into))
                                 }
                                 _ => (),
                             }
+
+                            if attr_or_derive_item.is_none() {
+                                if sema.is_attr_macro_call(InFile::new(file_id.into(), &item)) {
+                                    attr_or_derive_item = Some(AttrOrDerive::Attr(item));
+                                } else {
+                                    let adt = match item {
+                                        ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
+                                        ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
+                                        ast::Item::Union(it) => Some(ast::Adt::Union(it)),
+                                        _ => None,
+                                    };
+                                    match adt {
+                                        Some(adt)
+                                            if sema.is_derive_annotated(InFile::new(
+                                                file_id.into(),
+                                                &adt,
+                                            )) =>
+                                        {
+                                            attr_or_derive_item =
+                                                Some(AttrOrDerive::Derive(ast::Item::from(adt)));
+                                        }
+                                        _ => (),
+                                    }
+                                }
+                            }
                         }
+                        Either::Right(it) => body_stack.push(sema.to_def(&it).map(Into::into)),
                     }
                 }
             }
-            Leave(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => {
+            Leave(NodeOrToken::Node(node))
+                if <Either<ast::Item, ast::Variant>>::can_cast(node.kind()) =>
+            {
                 match ast::Item::cast(node.clone()) {
-                    Some(item)
-                        if attr_or_derive_item.as_ref().is_some_and(|it| *it.item() == item) =>
-                    {
-                        attr_or_derive_item = None;
+                    Some(item) => {
+                        if attr_or_derive_item.as_ref().is_some_and(|it| *it.item() == item) {
+                            attr_or_derive_item = None;
+                        }
+                        if matches!(
+                            item,
+                            ast::Item::Fn(_) | ast::Item::Const(_) | ast::Item::Static(_)
+                        ) {
+                            body_stack.pop();
+                        }
                     }
-                    _ => (),
+                    None => _ = body_stack.pop(),
                 }
             }
             _ => (),
@@ -361,16 +392,22 @@ fn traverse(
                 None => false,
             };
 
-        let descended_element = if in_macro {
+        let (descended_element, current_body) = match element {
             // Attempt to descend tokens into macro-calls.
-            match element {
-                NodeOrToken::Token(token) => descend_token(sema, InRealFile::new(file_id, token)),
-                n => InFile::new(file_id.into(), n),
+            NodeOrToken::Token(token) if in_macro => {
+                let descended = descend_token(sema, InRealFile::new(file_id, token));
+                let body = match &descended.value {
+                    NodeOrToken::Node(n) => {
+                        sema.body_for(InFile::new(descended.file_id, n.syntax()))
+                    }
+                    NodeOrToken::Token(t) => {
+                        t.parent().and_then(|it| sema.body_for(InFile::new(descended.file_id, &it)))
+                    }
+                };
+                (descended, body)
             }
-        } else {
-            InFile::new(file_id.into(), element)
+            n => (InFile::new(file_id.into(), n), body_stack.last().copied().flatten()),
         };
-
         // string highlight injections
         if let (Some(original_token), Some(descended_token)) =
             (original_token, descended_element.value.as_token())
@@ -390,12 +427,24 @@ fn traverse(
         }
 
         let edition = descended_element.file_id.edition(sema.db);
+        let (unsafe_ops, bindings_shadow_count) = match current_body {
+            Some(current_body) => {
+                let (ops, bindings) = per_body_cache
+                    .entry(current_body)
+                    .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default()));
+                (&*ops, Some(bindings))
+            }
+            None => (&empty, None),
+        };
+        let is_unsafe_node =
+            |node| unsafe_ops.contains(&InFile::new(descended_element.file_id, node));
         let element = match descended_element.value {
             NodeOrToken::Node(name_like) => {
                 let hl = highlight::name_like(
                     sema,
                     krate,
-                    &mut bindings_shadow_count,
+                    bindings_shadow_count,
+                    &is_unsafe_node,
                     config.syntactic_name_ref_highlighting,
                     name_like,
                     edition,
@@ -408,7 +457,8 @@ fn traverse(
                 hl
             }
             NodeOrToken::Token(token) => {
-                highlight::token(sema, token, edition, tt_level > 0).zip(Some(None))
+                highlight::token(sema, token, edition, &is_unsafe_node, tt_level > 0)
+                    .zip(Some(None))
             }
         };
         if let Some((mut highlight, binding_hash)) = element {
@@ -543,7 +593,7 @@ fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool
                 *tag = HlTag::Punctuation(HlPunct::Other);
             }
         }
-        HlTag::Punctuation(_) if !config.punctuation => return false,
+        HlTag::Punctuation(_) if !config.punctuation && highlight.mods.is_empty() => return false,
         tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => {
             *tag = HlTag::Punctuation(HlPunct::Other);
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
index c63043621c2..cc02aff2acf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
@@ -41,7 +41,7 @@ pub(super) fn highlight_format_string(
             if let Some(res) = res {
                 stack.add(HlRange {
                     range,
-                    highlight: highlight_def(sema, krate, Definition::from(res), edition),
+                    highlight: highlight_def(sema, krate, Definition::from(res), edition, true),
                     binding_hash: None,
                 })
             }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 127861a04bd..282fbb4433b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,17 +1,20 @@
 //! Computes color for a single element.
 
+use std::ops::ControlFlow;
+
 use either::Either;
 use hir::{AsAssocItem, HasVisibility, MacroFileIdExt, Semantics};
 use ide_db::{
     defs::{Definition, IdentClass, NameClass, NameRefClass},
+    syntax_helpers::node_ext::walk_pat,
     FxHashMap, RootDatabase, SymbolKind,
 };
 use span::Edition;
 use stdx::hash_once;
 use syntax::{
-    ast, match_ast, AstNode, AstToken, NodeOrToken,
+    ast, match_ast, AstNode, AstPtr, AstToken, NodeOrToken,
     SyntaxKind::{self, *},
-    SyntaxNode, SyntaxToken, T,
+    SyntaxNode, SyntaxNodePtr, SyntaxToken, T,
 };
 
 use crate::{
@@ -23,6 +26,7 @@ pub(super) fn token(
     sema: &Semantics<'_, RootDatabase>,
     token: SyntaxToken,
     edition: Edition,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
     in_tt: bool,
 ) -> Option<Highlight> {
     if let Some(comment) = ast::Comment::cast(token.clone()) {
@@ -33,11 +37,8 @@ pub(super) fn token(
         });
     }
 
-    let highlight: Highlight = match token.kind() {
+    let h = match token.kind() {
         STRING | BYTE_STRING | C_STRING => HlTag::StringLiteral.into(),
-        INT_NUMBER if token.parent_ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => {
-            SymbolKind::Field.into()
-        }
         INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
         BYTE => HlTag::ByteLiteral.into(),
         CHAR => HlTag::CharLiteral.into(),
@@ -46,24 +47,25 @@ pub(super) fn token(
             // that were not mapped down into macro invocations
             HlTag::None.into()
         }
-        p if p.is_punct() => punctuation(sema, token, p),
+        p if p.is_punct() => punctuation(sema, token, p, is_unsafe_node),
         k if k.is_keyword(edition) => {
             if in_tt && token.prev_token().is_some_and(|t| t.kind() == T![$]) {
                 // we are likely within a macro definition where our keyword is a fragment name
                 HlTag::None.into()
             } else {
-                keyword(sema, token, k)?
+                keyword(token, k)
             }
         }
         _ => return None,
     };
-    Some(highlight)
+    Some(h)
 }
 
 pub(super) fn name_like(
     sema: &Semantics<'_, RootDatabase>,
     krate: hir::Crate,
-    bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
+    bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
     syntactic_name_ref_highlighting: bool,
     name_like: ast::NameLike,
     edition: Edition,
@@ -75,19 +77,26 @@ pub(super) fn name_like(
             krate,
             bindings_shadow_count,
             &mut binding_hash,
+            is_unsafe_node,
             syntactic_name_ref_highlighting,
             name_ref,
             edition,
         ),
-        ast::NameLike::Name(name) => {
-            highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name, edition)
-        }
+        ast::NameLike::Name(name) => highlight_name(
+            sema,
+            bindings_shadow_count,
+            &mut binding_hash,
+            is_unsafe_node,
+            krate,
+            name,
+            edition,
+        ),
         ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) {
             Some(IdentClass::NameClass(NameClass::Definition(def))) => {
-                highlight_def(sema, krate, def, edition) | HlMod::Definition
+                highlight_def(sema, krate, def, edition, false) | HlMod::Definition
             }
             Some(IdentClass::NameRefClass(NameRefClass::Definition(def, _))) => {
-                highlight_def(sema, krate, def, edition)
+                highlight_def(sema, krate, def, edition, true)
             }
             // FIXME: Fallback for '_, as we do not resolve these yet
             _ => SymbolKind::LifetimeParam.into(),
@@ -100,44 +109,49 @@ fn punctuation(
     sema: &Semantics<'_, RootDatabase>,
     token: SyntaxToken,
     kind: SyntaxKind,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Highlight {
-    let parent = token.parent();
-    let parent_kind = parent.as_ref().map_or(EOF, SyntaxNode::kind);
-    match (kind, parent_kind) {
+    let operator_parent = token.parent();
+    let parent_kind = operator_parent.as_ref().map_or(EOF, SyntaxNode::kind);
+    let h = match (kind, parent_kind) {
         (T![?], TRY_EXPR) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
         (T![&], BIN_EXPR) => HlOperator::Bitwise.into(),
-        (T![&], REF_EXPR) => {
-            let h = HlTag::Operator(HlOperator::Other).into();
-            let is_unsafe = parent
-                .and_then(ast::RefExpr::cast)
-                .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr));
-            if let Some(true) = is_unsafe {
-                h | HlMod::Unsafe
+        (T![&], REF_EXPR | REF_PAT) => HlTag::Operator(HlOperator::Other).into(),
+        (T![..] | T![..=], _) => match token.parent().and_then(ast::Pat::cast) {
+            Some(pat) if is_unsafe_node(AstPtr::new(&pat).wrap_right()) => {
+                Highlight::from(HlOperator::Other) | HlMod::Unsafe
+            }
+            _ => HlOperator::Other.into(),
+        },
+        (T![::] | T![->] | T![=>] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(),
+        (T![!], MACRO_CALL) => {
+            if operator_parent
+                .and_then(ast::MacroCall::cast)
+                .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call))
+            {
+                Highlight::from(HlPunct::MacroBang) | HlMod::Unsafe
             } else {
-                h
+                HlPunct::MacroBang.into()
             }
         }
-        (T![::] | T![->] | T![=>] | T![..] | T![..=] | T![=] | T![@] | T![.], _) => {
-            HlOperator::Other.into()
-        }
-        (T![!], MACRO_CALL | MACRO_RULES) => HlPunct::MacroBang.into(),
+        (T![!], MACRO_RULES) => HlPunct::MacroBang.into(),
         (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
         (T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
         (T![*], PTR_TYPE) => HlTag::Keyword.into(),
         (T![*], PREFIX_EXPR) => {
-            let is_raw_ptr = (|| {
-                let prefix_expr = parent.and_then(ast::PrefixExpr::cast)?;
-                let expr = prefix_expr.expr()?;
-                sema.type_of_expr(&expr)?.original.is_raw_ptr().then_some(())
-            })();
-            if let Some(()) = is_raw_ptr {
-                HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
+            let h = HlTag::Operator(HlOperator::Other).into();
+            let ptr = operator_parent
+                .as_ref()
+                .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)));
+            if ptr.is_some_and(is_unsafe_node) {
+                h | HlMod::Unsafe
             } else {
-                HlOperator::Other.into()
+                h
             }
         }
         (T![-], PREFIX_EXPR) => {
-            let prefix_expr = parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr());
+            let prefix_expr =
+                operator_parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr());
             match prefix_expr {
                 Some(ast::Expr::Literal(_)) => HlTag::NumericLiteral,
                 _ => HlTag::Operator(HlOperator::Other),
@@ -157,36 +171,90 @@ fn punctuation(
             HlOperator::Comparison.into()
         }
         (_, ATTR) => HlTag::AttributeBracket.into(),
+        (T![>], _)
+            if operator_parent
+                .as_ref()
+                .and_then(SyntaxNode::parent)
+                .is_some_and(|it| it.kind() == MACRO_RULES) =>
+        {
+            HlOperator::Other.into()
+        }
         (kind, _) => match kind {
-            T!['['] | T![']'] => HlPunct::Bracket,
-            T!['{'] | T!['}'] => HlPunct::Brace,
-            T!['('] | T![')'] => HlPunct::Parenthesis,
-            T![>]
-                if parent
+            T!['['] | T![']'] => {
+                let is_unsafe_macro = operator_parent
                     .as_ref()
-                    .and_then(SyntaxNode::parent)
-                    .is_some_and(|it| it.kind() == MACRO_RULES) =>
-            {
-                return HlOperator::Other.into()
+                    .and_then(|it| ast::TokenTree::cast(it.clone())?.syntax().parent())
+                    .and_then(ast::MacroCall::cast)
+                    .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+                let is_unsafe = is_unsafe_macro
+                    || operator_parent
+                        .as_ref()
+                        .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)))
+                        .is_some_and(is_unsafe_node);
+                if is_unsafe {
+                    return Highlight::from(HlPunct::Bracket) | HlMod::Unsafe;
+                } else {
+                    HlPunct::Bracket
+                }
+            }
+            T!['{'] | T!['}'] => {
+                let is_unsafe_macro = operator_parent
+                    .as_ref()
+                    .and_then(|it| ast::TokenTree::cast(it.clone())?.syntax().parent())
+                    .and_then(ast::MacroCall::cast)
+                    .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+                let is_unsafe = is_unsafe_macro
+                    || operator_parent
+                        .as_ref()
+                        .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)))
+                        .is_some_and(is_unsafe_node);
+                if is_unsafe {
+                    return Highlight::from(HlPunct::Brace) | HlMod::Unsafe;
+                } else {
+                    HlPunct::Brace
+                }
+            }
+            T!['('] | T![')'] => {
+                let is_unsafe_macro = operator_parent
+                    .as_ref()
+                    .and_then(|it| ast::TokenTree::cast(it.clone())?.syntax().parent())
+                    .and_then(ast::MacroCall::cast)
+                    .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+                let is_unsafe = is_unsafe_macro
+                    || operator_parent
+                        .and_then(|it| {
+                            if ast::ArgList::can_cast(it.kind()) {
+                                it.parent()
+                            } else {
+                                Some(it)
+                            }
+                        })
+                        .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(&it)))
+                        .is_some_and(is_unsafe_node);
+
+                if is_unsafe {
+                    return Highlight::from(HlPunct::Parenthesis) | HlMod::Unsafe;
+                } else {
+                    HlPunct::Parenthesis
+                }
             }
             T![<] | T![>] => HlPunct::Angle,
-            T![,] => HlPunct::Comma,
+            // Early return as otherwise we'd highlight these in
+            // asm expressions
+            T![,] => return HlPunct::Comma.into(),
             T![:] => HlPunct::Colon,
             T![;] => HlPunct::Semi,
             T![.] => HlPunct::Dot,
             _ => HlPunct::Other,
         }
         .into(),
-    }
+    };
+    h
 }
 
-fn keyword(
-    sema: &Semantics<'_, RootDatabase>,
-    token: SyntaxToken,
-    kind: SyntaxKind,
-) -> Option<Highlight> {
+fn keyword(token: SyntaxToken, kind: SyntaxKind) -> Highlight {
     let h = Highlight::new(HlTag::Keyword);
-    let h = match kind {
+    match kind {
         T![await] => h | HlMod::Async | HlMod::ControlFlow,
         T![async] => h | HlMod::Async,
         T![break]
@@ -202,53 +270,33 @@ fn keyword(
         T![do] | T![yeet] if parent_matches::<ast::YeetExpr>(&token) => h | HlMod::ControlFlow,
         T![for] if parent_matches::<ast::ForExpr>(&token) => h | HlMod::ControlFlow,
         T![unsafe] => h | HlMod::Unsafe,
-        T![const]
-            if token.parent().is_some_and(|it| {
-                matches!(
-                    it.kind(),
-                    SyntaxKind::CONST
-                        | SyntaxKind::FN
-                        | SyntaxKind::IMPL
-                        | SyntaxKind::BLOCK_EXPR
-                        | SyntaxKind::CLOSURE_EXPR
-                        | SyntaxKind::FN_PTR_TYPE
-                        | SyntaxKind::TYPE_BOUND
-                        | SyntaxKind::CONST_BLOCK_PAT
-                )
-            }) =>
-        {
-            h | HlMod::Const
-        }
+        T![const] => h | HlMod::Const,
         T![true] | T![false] => HlTag::BoolLiteral.into(),
         // crate is handled just as a token if it's in an `extern crate`
         T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
-        T![ref] => match token.parent().and_then(ast::IdentPat::cast) {
-            Some(ident) if sema.is_unsafe_ident_pat(&ident) => h | HlMod::Unsafe,
-            _ => h,
-        },
         _ => h,
-    };
-    Some(h)
+    }
 }
 
 fn highlight_name_ref(
     sema: &Semantics<'_, RootDatabase>,
     krate: hir::Crate,
-    bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
+    bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
     binding_hash: &mut Option<u64>,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
     syntactic_name_ref_highlighting: bool,
     name_ref: ast::NameRef,
     edition: Edition,
 ) -> Highlight {
     let db = sema.db;
-    if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref, edition) {
+    if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref, is_unsafe_node) {
         return res;
     }
 
     let name_class = match NameRefClass::classify(sema, &name_ref) {
         Some(name_kind) => name_kind,
         None if syntactic_name_ref_highlighting => {
-            return highlight_name_ref_by_syntax(name_ref, sema, krate, edition)
+            return highlight_name_ref_by_syntax(name_ref, sema, krate, is_unsafe_node)
         }
         // FIXME: This is required for helper attributes used by proc-macros, as those do not map down
         // to anything when used.
@@ -267,17 +315,20 @@ fn highlight_name_ref(
     let mut h = match name_class {
         NameRefClass::Definition(def, _) => {
             if let Definition::Local(local) = &def {
-                let name = local.name(db);
-                let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
-                *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+                if let Some(bindings_shadow_count) = bindings_shadow_count {
+                    let name = local.name(sema.db);
+                    let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
+                    *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+                }
             };
 
-            let mut h = highlight_def(sema, krate, def, edition);
+            let mut h = highlight_def(sema, krate, def, edition, true);
 
             match def {
                 Definition::Local(local) if is_consumed_lvalue(name_ref.syntax(), &local, db) => {
                     h |= HlMod::Consuming;
                 }
+                // highlight unsafe traits as unsafe only in their implementations
                 Definition::Trait(trait_) if trait_.is_unsafe(db) => {
                     if ast::Impl::for_trait_name_ref(&name_ref)
                         .is_some_and(|impl_| impl_.unsafe_token().is_some())
@@ -285,23 +336,66 @@ fn highlight_name_ref(
                         h |= HlMod::Unsafe;
                     }
                 }
-                Definition::Field(field) => {
-                    if let Some(parent) = name_ref.syntax().parent() {
-                        if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
-                            if let hir::VariantDef::Union(_) = field.parent_def(db) {
-                                h |= HlMod::Unsafe;
-                            }
-                        }
+                Definition::Function(_) => {
+                    let is_unsafe = name_ref
+                        .syntax()
+                        .parent()
+                        .and_then(|it| ast::PathSegment::cast(it)?.parent_path().syntax().parent())
+                        .and_then(ast::PathExpr::cast)
+                        .and_then(|it| it.syntax().parent())
+                        .and_then(ast::CallExpr::cast)
+                        .is_some_and(|it| {
+                            is_unsafe_node(AstPtr::new(&ast::Expr::CallExpr(it)).wrap_left())
+                        });
+                    if is_unsafe {
+                        h |= HlMod::Unsafe;
                     }
                 }
                 Definition::Macro(_) => {
-                    if let Some(macro_call) =
-                        ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref)
-                            .and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast))
-                    {
-                        if sema.is_unsafe_macro_call(&macro_call) {
-                            h |= HlMod::Unsafe;
-                        }
+                    let is_unsafe = name_ref
+                        .syntax()
+                        .parent()
+                        .and_then(|it| ast::PathSegment::cast(it)?.parent_path().syntax().parent())
+                        .and_then(ast::MacroCall::cast)
+                        .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+                    if is_unsafe {
+                        h |= HlMod::Unsafe;
+                    }
+                }
+                Definition::Field(_) => {
+                    let is_unsafe = name_ref
+                        .syntax()
+                        .parent()
+                        .and_then(|it| {
+                            match_ast! { match it {
+                                ast::FieldExpr(expr) => Some(is_unsafe_node(AstPtr::new(&Either::Left(expr.into())))),
+                                ast::RecordPatField(pat) => {
+                                    walk_pat(&pat.pat()?, &mut |pat| {
+                                        if is_unsafe_node(AstPtr::new(&Either::Right(pat))) {
+                                            ControlFlow::Break(true)
+                                        }
+                                         else {ControlFlow::Continue(())}
+                                    }).break_value()
+                                },
+                                _ => None,
+                            }}
+                        })
+                        .unwrap_or(false);
+                    if is_unsafe {
+                        h |= HlMod::Unsafe;
+                    }
+                }
+                Definition::Static(_) => {
+                    let is_unsafe = name_ref
+                        .syntax()
+                        .parent()
+                        .and_then(|it| ast::PathSegment::cast(it)?.parent_path().syntax().parent())
+                        .and_then(ast::PathExpr::cast)
+                        .is_some_and(|it| {
+                            is_unsafe_node(AstPtr::new(&ast::Expr::PathExpr(it)).wrap_left())
+                        });
+                    if is_unsafe {
+                        h |= HlMod::Unsafe;
                     }
                 }
                 _ => (),
@@ -310,7 +404,7 @@ fn highlight_name_ref(
             h
         }
         NameRefClass::FieldShorthand { field_ref, .. } => {
-            highlight_def(sema, krate, field_ref.into(), edition)
+            highlight_def(sema, krate, field_ref.into(), edition, true)
         }
         NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => {
             let mut h = HlTag::Symbol(SymbolKind::Module).into();
@@ -342,22 +436,25 @@ fn highlight_name_ref(
 
 fn highlight_name(
     sema: &Semantics<'_, RootDatabase>,
-    bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
+    bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
     binding_hash: &mut Option<u64>,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
     krate: hir::Crate,
     name: ast::Name,
     edition: Edition,
 ) -> Highlight {
     let name_kind = NameClass::classify(sema, &name);
     if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
-        let name = local.name(sema.db);
-        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
-        *shadow_count += 1;
-        *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+        if let Some(bindings_shadow_count) = bindings_shadow_count {
+            let name = local.name(sema.db);
+            let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
+            *shadow_count += 1;
+            *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+        }
     };
     match name_kind {
         Some(NameClass::Definition(def)) => {
-            let mut h = highlight_def(sema, krate, def, edition) | HlMod::Definition;
+            let mut h = highlight_def(sema, krate, def, edition, false) | HlMod::Definition;
             if let Definition::Trait(trait_) = &def {
                 if trait_.is_unsafe(sema.db) {
                     h |= HlMod::Unsafe;
@@ -365,10 +462,14 @@ fn highlight_name(
             }
             h
         }
-        Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def, edition),
-        Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
+        Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def, edition, true),
+        Some(NameClass::PatFieldShorthand { .. }) => {
             let mut h = HlTag::Symbol(SymbolKind::Field).into();
-            if let hir::VariantDef::Union(_) = field_ref.parent_def(sema.db) {
+            let is_unsafe =
+                name.syntax().parent().and_then(ast::IdentPat::cast).is_some_and(|it| {
+                    is_unsafe_node(AstPtr::new(&ast::Pat::IdentPat(it)).wrap_right())
+                });
+            if is_unsafe {
                 h |= HlMod::Unsafe;
             }
             h
@@ -386,6 +487,7 @@ pub(super) fn highlight_def(
     krate: hir::Crate,
     def: Definition,
     edition: Edition,
+    is_ref: bool,
 ) -> Highlight {
     let db = sema.db;
     let mut h = match def {
@@ -439,7 +541,7 @@ pub(super) fn highlight_def(
             // We probably should consider checking the current function, but I found no easy way to do
             // that (also I'm worried about perf). There's also an instance below.
             // FIXME: This should be the edition of the call.
-            if func.is_unsafe_to_call(db, None, edition) {
+            if !is_ref && func.is_unsafe_to_call(db, None, edition) {
                 h |= HlMod::Unsafe;
             }
             if func.is_async(db) {
@@ -509,7 +611,9 @@ pub(super) fn highlight_def(
 
             if s.is_mut(db) {
                 h |= HlMod::Mutable;
-                h |= HlMod::Unsafe;
+                if !is_ref {
+                    h |= HlMod::Unsafe;
+                }
             }
 
             h
@@ -587,23 +691,24 @@ fn highlight_method_call_by_name_ref(
     sema: &Semantics<'_, RootDatabase>,
     krate: hir::Crate,
     name_ref: &ast::NameRef,
-    edition: Edition,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Option<Highlight> {
     let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
-    highlight_method_call(sema, krate, &mc, edition)
+    highlight_method_call(sema, krate, &mc, is_unsafe_node)
 }
 
 fn highlight_method_call(
     sema: &Semantics<'_, RootDatabase>,
     krate: hir::Crate,
     method_call: &ast::MethodCallExpr,
-    edition: Edition,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Option<Highlight> {
     let func = sema.resolve_method_call(method_call)?;
 
     let mut h = SymbolKind::Method.into();
 
-    if func.is_unsafe_to_call(sema.db, None, edition) || sema.is_unsafe_method_call(method_call) {
+    let is_unsafe = is_unsafe_node(AstPtr::new(method_call).upcast::<ast::Expr>().wrap_left());
+    if is_unsafe {
         h |= HlMod::Unsafe;
     }
     if func.is_async(sema.db) {
@@ -695,7 +800,7 @@ fn highlight_name_ref_by_syntax(
     name: ast::NameRef,
     sema: &Semantics<'_, RootDatabase>,
     krate: hir::Crate,
-    edition: Edition,
+    is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Highlight {
     let default = HlTag::UnresolvedReference;
 
@@ -707,19 +812,13 @@ fn highlight_name_ref_by_syntax(
     match parent.kind() {
         EXTERN_CRATE => HlTag::Symbol(SymbolKind::Module) | HlMod::CrateRoot,
         METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent)
-            .and_then(|it| highlight_method_call(sema, krate, &it, edition))
+            .and_then(|it| highlight_method_call(sema, krate, &it, is_unsafe_node))
             .unwrap_or_else(|| SymbolKind::Method.into()),
         FIELD_EXPR => {
             let h = HlTag::Symbol(SymbolKind::Field);
-            let is_union = ast::FieldExpr::cast(parent)
-                .and_then(|field_expr| sema.resolve_field(&field_expr))
-                .is_some_and(|field| match field {
-                    Either::Left(field) => {
-                        matches!(field.parent_def(sema.db), hir::VariantDef::Union(_))
-                    }
-                    Either::Right(_) => false,
-                });
-            if is_union {
+            let is_unsafe = ast::Expr::cast(parent)
+                .is_some_and(|it| is_unsafe_node(AstPtr::new(&it).wrap_left()));
+            if is_unsafe {
                 h | HlMod::Unsafe
             } else {
                 h.into()
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
index 47ad54759a8..07d40bafeba 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
@@ -88,12 +88,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -115,6 +109,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html
index 2bc22f960bd..c8ffa9e8558 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -49,26 +44,26 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
         <span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
         <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">o</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
-        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
+        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
             <span class="string_literal macro">"%input = OpLoad _ {</span><span class="variable">0</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
             <span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"%result = "</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="string_literal macro">" _ %input"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span>
             <span class="string_literal macro">"OpStore {</span><span class="variable">1</span><span class="string_literal macro">} %result"</span><span class="comma macro">,</span>
             <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="operator macro">&</span><span class="variable macro">foo</span><span class="comma macro">,</span>
             <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="operator macro">&</span><span class="keyword macro">mut</span> <span class="variable macro mutable">o</span><span class="comma macro">,</span>
-        <span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
 
         <span class="keyword">let</span> <span class="variable declaration">thread_id</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
-        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"
+        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span><span class="string_literal macro">"
             mov {</span><span class="variable">0</span><span class="string_literal macro">}, gs:[0x30]
             mov {</span><span class="variable">0</span><span class="string_literal macro">}, [{</span><span class="variable">0</span><span class="string_literal macro">}+0x48]
-        "</span><span class="comma macro">,</span> <span class="keyword macro">out</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">thread_id</span><span class="comma macro">,</span> <span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">pure</span><span class="comma macro">,</span> <span class="keyword macro">readonly</span><span class="comma macro">,</span> <span class="keyword macro">nostack</span><span class="parenthesis macro">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        "</span><span class="comma macro">,</span> <span class="keyword macro">out</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">thread_id</span><span class="comma macro">,</span> <span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">pure</span><span class="comma macro">,</span> <span class="keyword macro">readonly</span><span class="comma macro">,</span> <span class="keyword macro">nostack</span><span class="parenthesis macro">)</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
 
         <span class="keyword">static</span> <span class="static declaration">UNMAP_BASE</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
         <span class="keyword const">const</span> <span class="constant const declaration">MEM_RELEASE</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
         <span class="keyword">static</span> <span class="static declaration">VirtualFree</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
         <span class="keyword const">const</span> <span class="constant const declaration">OffPtr</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
         <span class="keyword const">const</span> <span class="constant const declaration">OffFn</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
-        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"
+        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span><span class="string_literal macro">"
             push {</span><span class="variable">free_type</span><span class="string_literal macro">}
             push {</span><span class="variable">free_size</span><span class="string_literal macro">}
             push {</span><span class="variable">base</span><span class="string_literal macro">}
@@ -82,26 +77,26 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
             jmp {</span><span class="variable">virtual_free</span><span class="string_literal macro">}
             "</span><span class="comma macro">,</span>
-            <span class="variable declaration macro">off_ptr</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="constant const macro">OffPtr</span><span class="comma macro">,</span>
-            <span class="variable declaration macro">off_fn</span>  <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="constant const macro">OffFn</span><span class="comma macro">,</span>
+            <span class="variable declaration macro">off_ptr</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="constant const macro">OffPtr</span><span class="comma macro">,</span>
+            <span class="variable declaration macro">off_fn</span>  <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="constant const macro">OffFn</span><span class="comma macro">,</span>
 
-            <span class="variable declaration macro">free_size</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="numeric_literal macro">0</span><span class="comma macro">,</span>
-            <span class="variable declaration macro">free_type</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="constant const macro">MEM_RELEASE</span><span class="comma macro">,</span>
+            <span class="variable declaration macro">free_size</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="numeric_literal macro">0</span><span class="comma macro">,</span>
+            <span class="variable declaration macro">free_type</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="constant const macro">MEM_RELEASE</span><span class="comma macro">,</span>
 
             <span class="variable declaration macro">virtual_free</span> <span class="operator macro">=</span> <span class="keyword macro">sym</span> <span class="static macro">VirtualFree</span><span class="comma macro">,</span>
 
             <span class="variable declaration macro">base</span> <span class="operator macro">=</span> <span class="keyword macro">sym</span> <span class="static macro">UNMAP_BASE</span><span class="comma macro">,</span>
             <span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">noreturn</span><span class="parenthesis macro">)</span><span class="comma macro">,</span>
-        <span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
 <span class="comment">// taken from https://github.com/rust-embedded/cortex-m/blob/47921b51f8b960344fcfa1255a50a0d19efcde6d/cortex-m/src/asm.rs#L254-L274</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">inline</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">pub</span> <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration public unsafe">bootstrap</span><span class="parenthesis">(</span><span class="value_param declaration">msp</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">u32</span><span class="comma">,</span> <span class="value_param declaration">rv</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">u32</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="brace">{</span>
+<span class="keyword">pub</span> <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration public unsafe">bootstrap</span><span class="parenthesis">(</span><span class="value_param declaration">msp</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="builtin_type">u32</span><span class="comma">,</span> <span class="value_param declaration">rv</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="builtin_type">u32</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="brace">{</span>
     <span class="comment">// Ensure thumb mode is set.</span>
     <span class="keyword">let</span> <span class="variable declaration">rv</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="value_param">rv</span> <span class="keyword">as</span> <span class="builtin_type">u32</span><span class="parenthesis">)</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">msp</span> <span class="operator">=</span> <span class="value_param">msp</span> <span class="keyword">as</span> <span class="builtin_type">u32</span><span class="semicolon">;</span>
-    <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
+    <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
         <span class="string_literal macro">"mrs {</span><span class="variable">tmp</span><span class="string_literal macro">}, CONTROL"</span><span class="comma macro">,</span>
         <span class="string_literal macro">"bics {</span><span class="variable">tmp</span><span class="string_literal macro">}, {</span><span class="variable">spsel</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
         <span class="string_literal macro">"msr CONTROL, {</span><span class="variable">tmp</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
@@ -115,5 +110,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="variable declaration macro">msp</span> <span class="operator macro">=</span> <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">msp</span><span class="comma macro">,</span>
         <span class="variable declaration macro">rv</span> <span class="operator macro">=</span> <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">rv</span><span class="comma macro">,</span>
         <span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">noreturn</span><span class="comma macro">,</span> <span class="keyword macro">nomem</span><span class="comma macro">,</span> <span class="keyword macro">nostack</span><span class="parenthesis macro">)</span><span class="comma macro">,</span>
-    <span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 9c7f03fc158..faace6eaff8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index e1d51dc0b71..d59f4caa97f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
index af29af3f03c..3beda396da8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -58,7 +53,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis">)</span><span class="semicolon">;</span>
         <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span>
             <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span>
-                <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
+                <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
             <span class="brace">}</span>
         <span class="brace">}</span>
     <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
index 6d8f6b3c6e3..9c7324eafa3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -50,21 +45,21 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span>
-<span class="keyword const">const</span> <span class="constant const declaration">CONST_ITEM</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-<span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function const declaration">const_fn</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">CONST_PARAM</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="keyword const">const</span> <span class="brace">{</span><span class="brace">}</span><span class="colon">:</span> <span class="keyword">const</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="keyword">where</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="brace">{</span>
+<span class="keyword const">const</span> <span class="constant const declaration">CONST_ITEM</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function const declaration">const_fn</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">CONST_PARAM</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="keyword const">const</span> <span class="brace">{</span><span class="brace">}</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="keyword">where</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="brace">{</span>
     <span class="constant const">CONST_ITEM</span><span class="semicolon">;</span>
     <span class="const_param const">CONST_PARAM</span><span class="semicolon">;</span>
     <span class="keyword const">const</span> <span class="brace">{</span>
-        <span class="keyword">const</span> <span class="punctuation">|</span><span class="punctuation">|</span> <span class="brace">{</span><span class="brace">}</span>
+        <span class="keyword const">const</span> <span class="punctuation">|</span><span class="punctuation">|</span> <span class="brace">{</span><span class="brace">}</span>
     <span class="brace">}</span>
     <span class="macro public">id</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
         <span class="constant const macro">CONST_ITEM</span><span class="semicolon macro">;</span>
         <span class="const_param const macro">CONST_PARAM</span><span class="semicolon macro">;</span>
         <span class="keyword const macro">const</span> <span class="brace macro">{</span>
-            <span class="keyword macro">const</span> <span class="punctuation macro">|</span><span class="punctuation macro">|</span> <span class="brace macro">{</span><span class="brace macro">}</span>
+            <span class="keyword const macro">const</span> <span class="punctuation macro">|</span><span class="punctuation macro">|</span> <span class="brace macro">{</span><span class="brace macro">}</span>
         <span class="brace macro">}</span><span class="semicolon macro">;</span>
-        <span class="operator macro">&</span><span class="keyword macro">raw</span> <span class="keyword macro">const</span> <span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon macro">;</span>
-        <span class="keyword macro">const</span>
+        <span class="operator macro">&</span><span class="keyword macro">raw</span> <span class="keyword const macro">const</span> <span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon macro">;</span>
+        <span class="keyword const macro">const</span>
     <span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="operator">.</span><span class="method const consuming trait">assoc_const_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
@@ -80,6 +75,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">unsafe_deref</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
-        <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+        <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
index 63e1560b921..4613c65ee61 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index dfad3a6605c..b1b2c659a22 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 263e4545fb5..c8c8c5dba4c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -129,7 +124,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// functions</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param const declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword const injected">const</span><span class="none injected"> </span><span class="const_param const declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="none injected">    </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="colon injected">:</span><span class="none injected"> </span><span class="type_param injected">T</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="const_param const injected">X</span><span class="semicolon injected">;</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="brace injected">}</span>
     <span class="comment documentation">/// ```</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index fe5f5ab6a9a..5399f83085e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index eb532a5639d..00925bd81ed 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -109,7 +104,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
+<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
     <span class="function">const_param</span><span class="operator">::</span><span class="angle">&lt;</span><span class="brace">{</span> <span class="const_param const">FOO</span> <span class="brace">}</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="const_param const">FOO</span>
 <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 1f9422161de..3b468ab6dba 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
index a846addba3f..5ef64465c98 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
index c3377614d72..0407e6896e9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
index 9b22500396b..f39d033c76f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
index 9b22500396b..f39d033c76f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
index ac8353120e8..721185a1a84 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
index 694e54d2fa8..b2c82051eb1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
index 8428b815800..618ea2171b5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index f224435e961..c3145941c3e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
index 947d1bf1e35..9996a871580 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
index 0fe2b6f274d..dc9e1de4a42 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index c60b6ab27bb..9c42401ed07 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
index a4449b5d8d8..7f6b4c2c880 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 539c74f6b57..f7d79820803 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -169,12 +164,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro public">toho</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
-    <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
+    <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
         <span class="string_literal macro">"mov {</span><span class="variable">0</span><span class="string_literal macro">}, {</span><span class="variable">1</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
         <span class="string_literal macro">"add {</span><span class="variable">0</span><span class="string_literal macro">}, 5"</span><span class="comma macro">,</span>
         <span class="keyword macro">out</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">o</span><span class="comma macro">,</span>
         <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">i</span><span class="comma macro">,</span>
-    <span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
 
     <span class="keyword const">const</span> <span class="constant const declaration">CONSTANT</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span>
     <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">m</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 9a46d9f4025..828b8f762c5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -14,12 +14,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .string_literal     { color: #CC9393; }
 .field              { color: #94BFF3; }
 .function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 .const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -52,78 +47,81 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">unsafe_deref</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
-        <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+        <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span>
-<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
-<span class="keyword">static</span> <span class="static declaration">GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
-<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">union</span> <span class="union declaration">Union</span> <span class="brace">{</span>
-    <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
-    <span class="field declaration">b</span><span class="colon">:</span> <span class="builtin_type">f32</span><span class="comma">,</span>
+    <span class="field declaration">field</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
 <span class="brace">}</span>
 
 <span class="keyword">struct</span> <span class="struct declaration">Struct</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="brace">}</span>
+
+<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
+<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+
 <span class="keyword">impl</span> <span class="struct">Struct</span> <span class="brace">{</span>
     <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
-    <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
-<span class="brace">}</span>
-
 <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">UnsafeTrait</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="struct">Packed</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="union">Union</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="keyword">impl</span> <span class="punctuation">!</span><span class="trait">UnsafeTrait</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">unsafe_trait_bound</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="colon">:</span> <span class="trait">UnsafeTrait</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
-<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="method associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-<span class="brace">}</span>
-
-<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="method associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">extern</span> <span class="brace">{</span>
+    <span class="keyword">static</span> <span class="static declaration">EXTERN_STATIC</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">x</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">u</span><span class="colon">:</span> <span class="union">Union</span><span class="semicolon">;</span>
 
+    <span class="comment">// id should be safe here, but unsafe_deref should not</span>
     <span class="macro public">id</span><span class="macro_bang">!</span> <span class="brace">{</span>
-        <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span>
+        <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro unsafe">!</span><span class="parenthesis macro unsafe">(</span><span class="parenthesis macro unsafe">)</span> <span class="brace macro">}</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 
     <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
-        <span class="macro public unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-        <span class="macro public unsafe">id</span><span class="macro_bang">!</span> <span class="brace">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace">}</span><span class="semicolon">;</span>
+        <span class="comment">// unsafe macro calls</span>
+        <span class="macro public unsafe">unsafe_deref</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+        <span class="macro public unsafe">id</span><span class="macro_bang unsafe">!</span> <span class="brace unsafe">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro unsafe">!</span><span class="parenthesis macro unsafe">(</span><span class="parenthesis macro unsafe">)</span> <span class="brace unsafe">}</span><span class="semicolon">;</span>
 
         <span class="comment">// unsafe fn and method calls</span>
-        <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-        <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
-        <span class="keyword control">match</span> <span class="variable">u</span> <span class="brace">{</span>
-            <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
-            <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
-        <span class="brace">}</span>
-        <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="operator">.</span><span class="method reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="function unsafe">unsafe_fn</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+        <span class="self_keyword crate_root public">self</span><span class="operator">::</span><span class="function unsafe">unsafe_fn</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+        <span class="parenthesis">(</span><span class="function">unsafe_fn</span> <span class="keyword">as</span> <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+        <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="operator">.</span><span class="method reference unsafe">unsafe_method</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+
+        <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+        <span class="comment">// this should be safe!</span>
+        <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="punctuation">_</span> <span class="brace">}</span><span class="semicolon">;</span>
+        <span class="comment">// but not these</span>
+        <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span> <span class="brace">}</span><span class="semicolon">;</span>
+        <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="variable declaration">field</span> <span class="brace">}</span><span class="semicolon">;</span>
+        <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="keyword">ref</span> <span class="variable declaration reference">field</span> <span class="brace">}</span><span class="semicolon">;</span>
+        <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="punctuation">_</span> <span class="punctuation">|</span> <span class="keyword">ref</span> <span class="variable declaration reference">field</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span>
 
         <span class="comment">// unsafe deref</span>
-        <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
+        <span class="operator unsafe">*</span><span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span><span class="operator">*</span><span class="operator">&</span><span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
 
         <span class="comment">// unsafe access to a static mut</span>
         <span class="static mutable unsafe">MUT_GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
-        <span class="static">GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
-
-        <span class="comment">// unsafe ref of packed fields</span>
-        <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
-        <span class="keyword">let</span> <span class="variable declaration reference">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
-        <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration reference">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
-        <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
-        <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration reference">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
-
-        <span class="comment">// unsafe auto ref of packed field</span>
-        <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="method reference trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="static mutable unsafe">MUT_GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="static mutable unsafe">MUT_GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
+        <span class="static mutable unsafe">MUT_GLOBAL</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="static mutable unsafe">MUT_GLOBAL</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="static mutable">MUT_GLOBAL</span><span class="semicolon">;</span>
+        <span class="static unsafe">EXTERN_STATIC</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="static unsafe">EXTERN_STATIC</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="static">EXTERN_STATIC</span><span class="semicolon">;</span>
+
+        <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
+            <span class="string_literal macro">"push {</span><span class="variable">base</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
+            <span class="variable declaration macro">base</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="numeric_literal macro">0</span>
+        <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index e48ca86c46b..8f69bb82300 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -589,7 +589,7 @@ fn main() {
 fn test_unsafe_highlighting() {
     check_highlighting(
         r#"
-//- minicore: sized
+//- minicore: sized, asm
 macro_rules! id {
     ($($tt:tt)*) => {
         $($tt)*
@@ -600,76 +600,79 @@ macro_rules! unsafe_deref {
         *(&() as *const ())
     };
 }
-static mut MUT_GLOBAL: Struct = Struct { field: 0 };
-static GLOBAL: Struct = Struct { field: 0 };
-unsafe fn unsafe_fn() {}
 
 union Union {
-    a: u32,
-    b: f32,
+    field: u32,
 }
 
 struct Struct { field: i32 }
+
+static mut MUT_GLOBAL: Struct = Struct { field: 0 };
+unsafe fn unsafe_fn() {}
+
 impl Struct {
     unsafe fn unsafe_method(&self) {}
 }
 
-#[repr(packed)]
-struct Packed {
-    a: u16,
-}
-
 unsafe trait UnsafeTrait {}
-unsafe impl UnsafeTrait for Packed {}
+unsafe impl UnsafeTrait for Union {}
 impl !UnsafeTrait for () {}
 
 fn unsafe_trait_bound<T: UnsafeTrait>(_: T) {}
 
-trait DoTheAutoref {
-    fn calls_autoref(&self);
-}
-
-impl DoTheAutoref for u16 {
-    fn calls_autoref(&self) {}
+extern {
+    static EXTERN_STATIC: ();
 }
 
 fn main() {
-    let x = &5 as *const _ as *const usize;
-    let u = Union { b: 0 };
+    let x: *const usize;
+    let u: Union;
 
+    // id should be safe here, but unsafe_deref should not
     id! {
         unsafe { unsafe_deref!() }
     };
 
     unsafe {
+        // unsafe macro calls
         unsafe_deref!();
         id! { unsafe_deref!() };
 
         // unsafe fn and method calls
         unsafe_fn();
-        let b = u.b;
-        match u {
-            Union { b: 0 } => (),
-            Union { a } => (),
-        }
+        self::unsafe_fn();
+        (unsafe_fn as unsafe fn())();
         Struct { field: 0 }.unsafe_method();
 
+        u.field;
+        &u.field;
+        &raw const u.field;
+        // this should be safe!
+        let Union { field: _ };
+        // but not these
+        let Union { field };
+        let Union { field: field };
+        let Union { field: ref field };
+        let Union { field: (_ | ref field) };
+
         // unsafe deref
-        *x;
+        *&raw const*&*x;
 
         // unsafe access to a static mut
         MUT_GLOBAL.field;
-        GLOBAL.field;
+        &MUT_GLOBAL.field;
+        &raw const MUT_GLOBAL.field;
+        MUT_GLOBAL;
+        &MUT_GLOBAL;
+        &raw const MUT_GLOBAL;
+        EXTERN_STATIC;
+        &EXTERN_STATIC;
+        &raw const EXTERN_STATIC;
 
-        // unsafe ref of packed fields
-        let packed = Packed { a: 0 };
-        let a = &packed.a;
-        let ref a = packed.a;
-        let Packed { ref a } = packed;
-        let Packed { a: ref _a } = packed;
-
-        // unsafe auto ref of packed field
-        packed.a.calls_autoref();
+        core::arch::asm!(
+            "push {base}",
+            base = const 0
+        );
     }
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index edb83bc4eac..34bca7bce12 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -1,12 +1,11 @@
 use std::fmt;
 
-use hir::{Field, HirDisplay, Layout, Semantics, Type};
+use hir::{DisplayTarget, Field, HirDisplay, Layout, Semantics, Type};
 use ide_db::{
     defs::Definition,
     helpers::{get_definition, pick_best_token},
     RootDatabase,
 };
-use span::Edition;
 use syntax::{AstNode, SyntaxKind};
 
 use crate::FilePosition;
@@ -84,10 +83,7 @@ pub(crate) fn view_memory_layout(
 ) -> Option<RecursiveMemoryLayout> {
     let sema = Semantics::new(db);
     let file = sema.parse_guess_edition(position.file_id);
-    let edition = sema
-        .attach_first_edition(position.file_id)
-        .map(|it| it.edition())
-        .unwrap_or(Edition::CURRENT);
+    let display_target = sema.first_crate_or_default(position.file_id).to_display_target(db);
     let token =
         pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
             SyntaxKind::IDENT => 3,
@@ -114,7 +110,7 @@ pub(crate) fn view_memory_layout(
         ty: &Type,
         layout: &Layout,
         parent_idx: usize,
-        edition: Edition,
+        display_target: DisplayTarget,
     ) {
         let mut fields = ty
             .fields(db)
@@ -145,7 +141,7 @@ pub(crate) fn view_memory_layout(
             if let Ok(child_layout) = child_ty.layout(db) {
                 nodes.push(MemoryLayoutNode {
                     item_name: field.name(db),
-                    typename: child_ty.display(db, edition).to_string(),
+                    typename: child_ty.display(db, display_target).to_string(),
                     size: child_layout.size(),
                     alignment: child_layout.align(),
                     offset: match *field {
@@ -161,7 +157,7 @@ pub(crate) fn view_memory_layout(
                     item_name: field.name(db)
                         + format!("(no layout data: {:?})", child_ty.layout(db).unwrap_err())
                             .as_ref(),
-                    typename: child_ty.display(db, edition).to_string(),
+                    typename: child_ty.display(db, display_target).to_string(),
                     size: 0,
                     offset: 0,
                     alignment: 0,
@@ -174,7 +170,7 @@ pub(crate) fn view_memory_layout(
 
         for (i, (_, child_ty)) in fields.iter().enumerate() {
             if let Ok(child_layout) = child_ty.layout(db) {
-                read_layout(nodes, db, child_ty, &child_layout, children_start + i, edition);
+                read_layout(nodes, db, child_ty, &child_layout, children_start + i, display_target);
             }
         }
     }
@@ -192,7 +188,7 @@ pub(crate) fn view_memory_layout(
                 def => def.name(db).map(|n| n.as_str().to_owned()).unwrap_or("[ROOT]".to_owned()),
             };
 
-            let typename = ty.display(db, edition).to_string();
+            let typename = ty.display(db, display_target).to_string();
 
             let mut nodes = vec![MemoryLayoutNode {
                 item_name,
@@ -204,7 +200,7 @@ pub(crate) fn view_memory_layout(
                 children_start: -1,
                 children_len: 0,
             }];
-            read_layout(&mut nodes, db, &ty, &layout, 0, edition);
+            read_layout(&mut nodes, db, &ty, &layout, 0, display_target);
 
             RecursiveMemoryLayout { nodes }
         })
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
index b3bf285edfb..0fa6701ca3f 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
@@ -18,20 +18,17 @@ use triomphe::Arc;
 pub mod symbols;
 
 // some asserts for layout compatibility
-const _: () = assert!(std::mem::size_of::<Box<str>>() == std::mem::size_of::<&str>());
-const _: () = assert!(std::mem::align_of::<Box<str>>() == std::mem::align_of::<&str>());
+const _: () = assert!(size_of::<Box<str>>() == size_of::<&str>());
+const _: () = assert!(align_of::<Box<str>>() == align_of::<&str>());
 
-const _: () = assert!(std::mem::size_of::<Arc<Box<str>>>() == std::mem::size_of::<&&str>());
-const _: () = assert!(std::mem::align_of::<Arc<Box<str>>>() == std::mem::align_of::<&&str>());
+const _: () = assert!(size_of::<Arc<Box<str>>>() == size_of::<&&str>());
+const _: () = assert!(align_of::<Arc<Box<str>>>() == align_of::<&&str>());
 
-const _: () =
-    assert!(std::mem::size_of::<*const *const str>() == std::mem::size_of::<TaggedArcPtr>());
-const _: () =
-    assert!(std::mem::align_of::<*const *const str>() == std::mem::align_of::<TaggedArcPtr>());
+const _: () = assert!(size_of::<*const *const str>() == size_of::<TaggedArcPtr>());
+const _: () = assert!(align_of::<*const *const str>() == align_of::<TaggedArcPtr>());
 
-const _: () = assert!(std::mem::size_of::<Arc<Box<str>>>() == std::mem::size_of::<TaggedArcPtr>());
-const _: () =
-    assert!(std::mem::align_of::<Arc<Box<str>>>() == std::mem::align_of::<TaggedArcPtr>());
+const _: () = assert!(size_of::<Arc<Box<str>>>() == size_of::<TaggedArcPtr>());
+const _: () = assert!(align_of::<Arc<Box<str>>>() == align_of::<TaggedArcPtr>());
 
 /// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or
 /// `Arc<Box<str>>` but its size is that of a thin pointer. The active variant is encoded as a tag
@@ -49,9 +46,7 @@ impl TaggedArcPtr {
     const BOOL_BITS: usize = true as usize;
 
     const fn non_arc(r: &'static &'static str) -> Self {
-        assert!(
-            mem::align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS
-        );
+        assert!(align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS);
         // SAFETY: The pointer is non-null as it is derived from a reference
         // Ideally we would call out to `pack_arc` but for a `false` tag, unfortunately the
         // packing stuff requires reading out the pointer to an integer which is not supported
@@ -64,9 +59,7 @@ impl TaggedArcPtr {
     }
 
     fn arc(arc: Arc<Box<str>>) -> Self {
-        assert!(
-            mem::align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS
-        );
+        assert!(align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS);
         Self {
             packed: Self::pack_arc(
                 // Safety: `Arc::into_raw` always returns a non null pointer
@@ -131,8 +124,8 @@ impl fmt::Debug for Symbol {
     }
 }
 
-const _: () = assert!(std::mem::size_of::<Symbol>() == std::mem::size_of::<NonNull<()>>());
-const _: () = assert!(std::mem::align_of::<Symbol>() == std::mem::align_of::<NonNull<()>>());
+const _: () = assert!(size_of::<Symbol>() == size_of::<NonNull<()>>());
+const _: () = assert!(align_of::<Symbol>() == align_of::<NonNull<()>>());
 
 static MAP: OnceLock<DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>>> = OnceLock::new();
 
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index be0de6c9366..6b77c72cee8 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -185,6 +185,7 @@ define_symbols! {
     Clone,
     coerce_unsized,
     column,
+    completion,
     compile_error,
     concat_bytes,
     concat_idents,
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 76f1a7f48b6..72ca85c6a2f 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -45,10 +45,18 @@ pub fn load_workspace_at(
 ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> {
     let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root));
     let root = ProjectManifest::discover_single(&root)?;
+    let manifest_path = root.manifest_path().clone();
     let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?;
 
     if load_config.load_out_dirs_from_check {
         let build_scripts = workspace.run_build_scripts(cargo_config, progress)?;
+        if let Some(error) = build_scripts.error() {
+            tracing::debug!(
+                "Errors occurred while running build scripts for {}: {}",
+                manifest_path,
+                error
+            );
+        }
         workspace.set_build_scripts(build_scripts)
     }
 
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
index fb68d35a4c8..4a73b6fa05a 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
@@ -100,6 +100,23 @@ fn check(
 }
 
 #[test]
+fn unbalanced_brace() {
+    check(
+        Edition::CURRENT,
+        Edition::CURRENT,
+        r#"
+() => { { }
+"#,
+        r#""#,
+        expect![[r#"
+            SUBTREE $$ 1:0@0..0#2 1:0@0..0#2
+              SUBTREE {} 0:0@9..10#2 0:0@11..12#2
+
+            {}"#]],
+    );
+}
+
+#[test]
 fn token_mapping_smoke_test() {
     check(
         Edition::CURRENT,
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index e56e09eeb66..1ff0bbea8b1 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -315,6 +315,7 @@ pub enum SyntaxKind {
     USE_TREE,
     USE_TREE_LIST,
     VARIANT,
+    VARIANT_DEF,
     VARIANT_LIST,
     VISIBILITY,
     WHERE_CLAUSE,
@@ -501,6 +502,7 @@ impl SyntaxKind {
             | USE_TREE
             | USE_TREE_LIST
             | VARIANT
+            | VARIANT_DEF
             | VARIANT_LIST
             | VISIBILITY
             | WHERE_CLAUSE
diff --git a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
index 006748ddb08..f5b8eca060f 100644
--- a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
@@ -38,7 +38,7 @@ impl MemoryUsage {
                 // approximate that by using the Commit Charge value.
 
                 use windows_sys::Win32::System::{Threading::*, ProcessStatus::*};
-                use std::mem::{MaybeUninit, size_of};
+                use std::mem::MaybeUninit;
 
                 let proc = unsafe { GetCurrentProcess() };
                 let mut mem_counters = MaybeUninit::uninit();
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 40ab8c53fae..014028a0b63 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -288,7 +288,23 @@ impl CargoWorkspace {
         locked: bool,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
-        Self::fetch_metadata_(cargo_toml, current_dir, config, sysroot, locked, false, progress)
+        let res = Self::fetch_metadata_(
+            cargo_toml,
+            current_dir,
+            config,
+            sysroot,
+            locked,
+            false,
+            progress,
+        );
+        if let Ok((_, Some(ref e))) = res {
+            tracing::warn!(
+                %cargo_toml,
+                ?e,
+                "`cargo metadata` failed, but retry with `--no-deps` succeeded"
+            );
+        }
+        res
     }
 
     fn fetch_metadata_(
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index 0282a714645..b2df8e4703a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -86,7 +86,7 @@ impl ProjectJson {
     /// * `manifest` - The path to the `rust-project.json`.
     /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
     /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
-    ///            configuration.
+    ///   configuration.
     pub fn new(
         manifest: Option<ManifestPath>,
         base: &AbsPath,
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 1e3c5a94786..13812e96fe7 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -30,6 +30,7 @@ pub struct Sysroot {
 pub enum RustLibSrcWorkspace {
     Workspace(CargoWorkspace),
     Json(ProjectJson),
+    Stitched(stitched::Stitched),
     Empty,
 }
 
@@ -60,6 +61,7 @@ impl Sysroot {
         match &self.workspace {
             RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
             RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
+            RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
             RustLibSrcWorkspace::Empty => true,
         }
     }
@@ -72,6 +74,7 @@ impl Sysroot {
         match &self.workspace {
             RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
             RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
+            RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.len(),
             RustLibSrcWorkspace::Empty => 0,
         }
     }
@@ -197,6 +200,51 @@ impl Sysroot {
                     return Some(loaded);
                 }
             }
+            tracing::debug!("Stitching sysroot library: {src_root}");
+
+            let mut stitched = stitched::Stitched { crates: Default::default() };
+
+            for path in stitched::SYSROOT_CRATES.trim().lines() {
+                let name = path.split('/').next_back().unwrap();
+                let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")]
+                    .into_iter()
+                    .map(|it| src_root.join(it))
+                    .filter_map(|it| ManifestPath::try_from(it).ok())
+                    .find(|it| fs::metadata(it).is_ok());
+
+                if let Some(root) = root {
+                    stitched.crates.alloc(stitched::RustLibSrcCrateData {
+                        name: name.into(),
+                        root,
+                        deps: Vec::new(),
+                    });
+                }
+            }
+
+            if let Some(std) = stitched.by_name("std") {
+                for dep in stitched::STD_DEPS.trim().lines() {
+                    if let Some(dep) = stitched.by_name(dep) {
+                        stitched.crates[std].deps.push(dep)
+                    }
+                }
+            }
+
+            if let Some(alloc) = stitched.by_name("alloc") {
+                for dep in stitched::ALLOC_DEPS.trim().lines() {
+                    if let Some(dep) = stitched.by_name(dep) {
+                        stitched.crates[alloc].deps.push(dep)
+                    }
+                }
+            }
+
+            if let Some(proc_macro) = stitched.by_name("proc_macro") {
+                for dep in stitched::PROC_MACRO_DEPS.trim().lines() {
+                    if let Some(dep) = stitched.by_name(dep) {
+                        stitched.crates[proc_macro].deps.push(dep)
+                    }
+                }
+            }
+            return Some(RustLibSrcWorkspace::Stitched(stitched));
         } else if let RustSourceWorkspaceConfig::Json(project_json) = sysroot_source_config {
             return Some(RustLibSrcWorkspace::Json(project_json.clone()));
         }
@@ -216,6 +264,7 @@ impl Sysroot {
                         .crates()
                         .filter_map(|(_, krate)| krate.display_name.clone())
                         .any(|name| name.canonical_name().as_str() == "core"),
+                    RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
                     RustLibSrcWorkspace::Empty => true,
                 };
                 if !has_core {
@@ -391,3 +440,91 @@ fn get_rust_lib_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
         None
     }
 }
+
+// FIXME: Remove this, that will bump our project MSRV to 1.82
+pub(crate) mod stitched {
+    use std::ops;
+
+    use base_db::CrateName;
+    use la_arena::{Arena, Idx};
+
+    use crate::ManifestPath;
+
+    #[derive(Debug, Clone, Eq, PartialEq)]
+    pub struct Stitched {
+        pub(super) crates: Arena<RustLibSrcCrateData>,
+    }
+
+    impl ops::Index<RustLibSrcCrate> for Stitched {
+        type Output = RustLibSrcCrateData;
+        fn index(&self, index: RustLibSrcCrate) -> &RustLibSrcCrateData {
+            &self.crates[index]
+        }
+    }
+
+    impl Stitched {
+        pub(crate) fn public_deps(
+            &self,
+        ) -> impl Iterator<Item = (CrateName, RustLibSrcCrate, bool)> + '_ {
+            // core is added as a dependency before std in order to
+            // mimic rustcs dependency order
+            [("core", true), ("alloc", false), ("std", true), ("test", false)]
+                .into_iter()
+                .filter_map(move |(name, prelude)| {
+                    Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
+                })
+        }
+
+        pub(crate) fn proc_macro(&self) -> Option<RustLibSrcCrate> {
+            self.by_name("proc_macro")
+        }
+
+        pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = RustLibSrcCrate> + '_ {
+            self.crates.iter().map(|(id, _data)| id)
+        }
+
+        pub(super) fn by_name(&self, name: &str) -> Option<RustLibSrcCrate> {
+            let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
+            Some(id)
+        }
+    }
+
+    pub(crate) type RustLibSrcCrate = Idx<RustLibSrcCrateData>;
+
+    #[derive(Debug, Clone, Eq, PartialEq)]
+    pub(crate) struct RustLibSrcCrateData {
+        pub(crate) name: String,
+        pub(crate) root: ManifestPath,
+        pub(crate) deps: Vec<RustLibSrcCrate>,
+    }
+
+    pub(super) const SYSROOT_CRATES: &str = "
+alloc
+backtrace
+core
+panic_abort
+panic_unwind
+proc_macro
+profiler_builtins
+std
+stdarch/crates/std_detect
+test
+unwind";
+
+    pub(super) const ALLOC_DEPS: &str = "core";
+
+    pub(super) const STD_DEPS: &str = "
+alloc
+panic_unwind
+panic_abort
+core
+profiler_builtins
+unwind
+std_detect
+test";
+
+    // core is required for our builtin derives to work in the proc_macro lib currently
+    pub(super) const PROC_MACRO_DEPS: &str = "
+std
+core";
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index cfc666970bd..83740622732 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -166,7 +166,7 @@ fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) {
 #[test]
 fn cargo_hello_world_project_model_with_wildcard_overrides() {
     let cfg_overrides = CfgOverrides {
-        global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(),
+        global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]),
         selective: Default::default(),
     };
     let (crate_graph, _proc_macros) =
@@ -185,7 +185,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
         global: Default::default(),
         selective: std::iter::once((
             "libc".to_owned(),
-            CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(),
+            CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]),
         ))
         .collect(),
     };
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 2c9f41e828e..62c13c7d9ec 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -692,6 +692,7 @@ impl ProjectWorkspace {
                         exclude: krate.exclude.clone(),
                     })
                     .collect(),
+                RustLibSrcWorkspace::Stitched(_) => vec![],
                 RustLibSrcWorkspace::Empty => vec![],
             };
 
@@ -1521,7 +1522,7 @@ fn extend_crate_graph_with_sysroot(
 ) -> (SysrootPublicDeps, Option<CrateId>) {
     let mut pub_deps = vec![];
     let mut libproc_macro = None;
-    let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]).unwrap();
+    let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]);
     for (cid, c) in sysroot_crate_graph.iter_mut() {
         // uninject `test` flag so `core` keeps working.
         Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
@@ -1599,8 +1600,7 @@ fn sysroot_to_crate_graph(
                             CfgAtom::Flag(sym::miri.clone()),
                         ],
                         vec![],
-                    )
-                    .unwrap(),
+                    ),
                     ..Default::default()
                 },
                 &WorkspaceBuildScripts::default(),
@@ -1623,8 +1623,7 @@ fn sysroot_to_crate_graph(
                             CfgAtom::Flag(sym::miri.clone()),
                         ],
                         vec![],
-                    )
-                    .unwrap(),
+                    ),
                     ..Default::default()
                 },
                 false,
@@ -1632,7 +1631,62 @@ fn sysroot_to_crate_graph(
 
             extend_crate_graph_with_sysroot(crate_graph, cg, pm)
         }
+        RustLibSrcWorkspace::Stitched(stitched) => {
+            let cfg_options = Arc::new({
+                let mut cfg_options = CfgOptions::default();
+                cfg_options.extend(rustc_cfg);
+                cfg_options.insert_atom(sym::debug_assertions.clone());
+                cfg_options.insert_atom(sym::miri.clone());
+                cfg_options
+            });
+            let sysroot_crates: FxHashMap<crate::sysroot::stitched::RustLibSrcCrate, CrateId> =
+                stitched
+                    .crates()
+                    .filter_map(|krate| {
+                        let file_id = load(&stitched[krate].root)?;
+
+                        let display_name =
+                            CrateDisplayName::from_canonical_name(&stitched[krate].name);
+                        let crate_id = crate_graph.add_crate_root(
+                            file_id,
+                            Edition::CURRENT_FIXME,
+                            Some(display_name),
+                            None,
+                            cfg_options.clone(),
+                            None,
+                            Env::default(),
+                            CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
+                            false,
+                            None,
+                        );
+                        Some((krate, crate_id))
+                    })
+                    .collect();
+
+            for from in stitched.crates() {
+                for &to in stitched[from].deps.iter() {
+                    let name = CrateName::new(&stitched[to].name).unwrap();
+                    if let (Some(&from), Some(&to)) =
+                        (sysroot_crates.get(&from), sysroot_crates.get(&to))
+                    {
+                        add_dep(crate_graph, from, name, to);
+                    }
+                }
+            }
+
+            let public_deps = SysrootPublicDeps {
+                deps: stitched
+                    .public_deps()
+                    .filter_map(|(name, idx, prelude)| {
+                        Some((name, *sysroot_crates.get(&idx)?, prelude))
+                    })
+                    .collect::<Vec<_>>(),
+            };
 
+            let libproc_macro =
+                stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
+            (public_deps, libproc_macro)
+        }
         RustLibSrcWorkspace::Empty => (SysrootPublicDeps { deps: vec![] }, None),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 28ca4eb5348..9b4be19c41c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -3,6 +3,417 @@
         root_file_id: FileId(
             1,
         ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "alloc",
+                ),
+                canonical_name: "alloc",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+        ],
+        origin: Lang(
+            Alloc,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    1: CrateData {
+        root_file_id: FileId(
+            2,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "core",
+                ),
+                canonical_name: "core",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Core,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    2: CrateData {
+        root_file_id: FileId(
+            3,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "panic_abort",
+                ),
+                canonical_name: "panic_abort",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    3: CrateData {
+        root_file_id: FileId(
+            4,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "panic_unwind",
+                ),
+                canonical_name: "panic_unwind",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    4: CrateData {
+        root_file_id: FileId(
+            5,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "proc_macro",
+                ),
+                canonical_name: "proc_macro",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(6),
+                name: CrateName(
+                    "std",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+        ],
+        origin: Lang(
+            ProcMacro,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    5: CrateData {
+        root_file_id: FileId(
+            6,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "profiler_builtins",
+                ),
+                canonical_name: "profiler_builtins",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    6: CrateData {
+        root_file_id: FileId(
+            7,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "std",
+                ),
+                canonical_name: "std",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(0),
+                name: CrateName(
+                    "alloc",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(3),
+                name: CrateName(
+                    "panic_unwind",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(2),
+                name: CrateName(
+                    "panic_abort",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(5),
+                name: CrateName(
+                    "profiler_builtins",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(9),
+                name: CrateName(
+                    "unwind",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(7),
+                name: CrateName(
+                    "std_detect",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "test",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+        ],
+        origin: Lang(
+            Std,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    7: CrateData {
+        root_file_id: FileId(
+            8,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "std_detect",
+                ),
+                canonical_name: "std_detect",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    8: CrateData {
+        root_file_id: FileId(
+            9,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "test",
+                ),
+                canonical_name: "test",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Test,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    9: CrateData {
+        root_file_id: FileId(
+            10,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "unwind",
+                ),
+                canonical_name: "unwind",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    10: CrateData {
+        root_file_id: FileId(
+            11,
+        ),
         edition: Edition2018,
         version: None,
         display_name: Some(
@@ -27,7 +438,48 @@
         env: Env {
             entries: {},
         },
-        dependencies: [],
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(0),
+                name: CrateName(
+                    "alloc",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(6),
+                name: CrateName(
+                    "std",
+                ),
+                prelude: true,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "test",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(4),
+                name: CrateName(
+                    "proc_macro",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+        ],
         origin: Local {
             repo: None,
             name: Some(
@@ -37,9 +489,9 @@
         is_proc_macro: false,
         proc_macro_cwd: None,
     },
-    1: CrateData {
+    11: CrateData {
         root_file_id: FileId(
-            1,
+            11,
         ),
         edition: Edition2018,
         version: None,
@@ -65,7 +517,48 @@
         env: Env {
             entries: {},
         },
-        dependencies: [],
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(0),
+                name: CrateName(
+                    "alloc",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(6),
+                name: CrateName(
+                    "std",
+                ),
+                prelude: true,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "test",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(4),
+                name: CrateName(
+                    "proc_macro",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+        ],
         origin: Local {
             repo: None,
             name: Some(
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index dde8d3023dc..4c8e66e8e96 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -3,6 +3,417 @@
         root_file_id: FileId(
             1,
         ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "alloc",
+                ),
+                canonical_name: "alloc",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+        ],
+        origin: Lang(
+            Alloc,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    1: CrateData {
+        root_file_id: FileId(
+            2,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "core",
+                ),
+                canonical_name: "core",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Core,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    2: CrateData {
+        root_file_id: FileId(
+            3,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "panic_abort",
+                ),
+                canonical_name: "panic_abort",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    3: CrateData {
+        root_file_id: FileId(
+            4,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "panic_unwind",
+                ),
+                canonical_name: "panic_unwind",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    4: CrateData {
+        root_file_id: FileId(
+            5,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "proc_macro",
+                ),
+                canonical_name: "proc_macro",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(6),
+                name: CrateName(
+                    "std",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+        ],
+        origin: Lang(
+            ProcMacro,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    5: CrateData {
+        root_file_id: FileId(
+            6,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "profiler_builtins",
+                ),
+                canonical_name: "profiler_builtins",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    6: CrateData {
+        root_file_id: FileId(
+            7,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "std",
+                ),
+                canonical_name: "std",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(0),
+                name: CrateName(
+                    "alloc",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(3),
+                name: CrateName(
+                    "panic_unwind",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(2),
+                name: CrateName(
+                    "panic_abort",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(5),
+                name: CrateName(
+                    "profiler_builtins",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(9),
+                name: CrateName(
+                    "unwind",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(7),
+                name: CrateName(
+                    "std_detect",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "test",
+                ),
+                prelude: true,
+                sysroot: false,
+            },
+        ],
+        origin: Lang(
+            Std,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    7: CrateData {
+        root_file_id: FileId(
+            8,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "std_detect",
+                ),
+                canonical_name: "std_detect",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    8: CrateData {
+        root_file_id: FileId(
+            9,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "test",
+                ),
+                canonical_name: "test",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Test,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    9: CrateData {
+        root_file_id: FileId(
+            10,
+        ),
+        edition: Edition2021,
+        version: None,
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "unwind",
+                ),
+                canonical_name: "unwind",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "miri",
+                "true",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {},
+        },
+        dependencies: [],
+        origin: Lang(
+            Other,
+        ),
+        is_proc_macro: false,
+        proc_macro_cwd: None,
+    },
+    10: CrateData {
+        root_file_id: FileId(
+            11,
+        ),
         edition: Edition2018,
         version: None,
         display_name: Some(
@@ -24,7 +435,48 @@
         env: Env {
             entries: {},
         },
-        dependencies: [],
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "core",
+                ),
+                prelude: true,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(0),
+                name: CrateName(
+                    "alloc",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(6),
+                name: CrateName(
+                    "std",
+                ),
+                prelude: true,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "test",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(4),
+                name: CrateName(
+                    "proc_macro",
+                ),
+                prelude: false,
+                sysroot: true,
+            },
+        ],
         origin: Local {
             repo: None,
             name: Some(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 4fc6180920f..dee76ee15c3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -69,7 +69,7 @@ impl flags::AnalysisStats {
             all_targets: true,
             set_test: !self.no_test,
             cfg_overrides: CfgOverrides {
-                global: CfgDiff::new(vec![CfgAtom::Flag(hir::sym::miri.clone())], vec![]).unwrap(),
+                global: CfgDiff::new(vec![CfgAtom::Flag(hir::sym::miri.clone())], vec![]),
                 selective: Default::default(),
             },
             ..Default::default()
@@ -390,6 +390,8 @@ impl flags::AnalysisStats {
 
         for &file_id in &file_ids {
             let sema = hir::Semantics::new(db);
+            let display_target =
+                sema.first_crate_or_default(file_id.file_id()).to_display_target(db);
 
             let parse = sema.parse_guess_edition(file_id.into());
             let file_txt = db.file_text(file_id.into());
@@ -467,7 +469,7 @@ impl flags::AnalysisStats {
                                 prefer_absolute: false,
                                 allow_unstable: true,
                             },
-                            Edition::LATEST,
+                            display_target,
                         )
                         .unwrap();
                     syntax_hit_found |= trim(&original_text) == trim(&generated);
@@ -641,6 +643,7 @@ impl flags::AnalysisStats {
         for &body_id in bodies {
             let name = body_id.name(db).unwrap_or_else(Name::missing);
             let module = body_id.module(db);
+            let display_target = module.krate().to_display_target(db);
             let full_name = move || {
                 module
                     .krate()
@@ -739,12 +742,12 @@ impl flags::AnalysisStats {
                             start.col,
                             end.line + 1,
                             end.col,
-                            ty.display(db, Edition::LATEST)
+                            ty.display(db, display_target)
                         ));
                     } else {
                         bar.println(format!(
                             "unknown location: {}",
-                            ty.display(db, Edition::LATEST)
+                            ty.display(db, display_target)
                         ));
                     }
                 }
@@ -752,7 +755,7 @@ impl flags::AnalysisStats {
                     println!(
                         r#"{},type,"{}""#,
                         location_csv_expr(db, vfs, &sm(), expr_id),
-                        ty.display(db, Edition::LATEST)
+                        ty.display(db, display_target)
                     );
                 }
                 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
@@ -767,15 +770,15 @@ impl flags::AnalysisStats {
                                 start.col,
                                 end.line + 1,
                                 end.col,
-                                mismatch.expected.display(db, Edition::LATEST),
-                                mismatch.actual.display(db, Edition::LATEST)
+                                mismatch.expected.display(db, display_target),
+                                mismatch.actual.display(db, display_target)
                             ));
                         } else {
                             bar.println(format!(
                                 "{}: Expected {}, got {}",
                                 name.display(db, Edition::LATEST),
-                                mismatch.expected.display(db, Edition::LATEST),
-                                mismatch.actual.display(db, Edition::LATEST)
+                                mismatch.expected.display(db, display_target),
+                                mismatch.actual.display(db, display_target)
                             ));
                         }
                     }
@@ -783,8 +786,8 @@ impl flags::AnalysisStats {
                         println!(
                             r#"{},mismatch,"{}","{}""#,
                             location_csv_expr(db, vfs, &sm(), expr_id),
-                            mismatch.expected.display(db, Edition::LATEST),
-                            mismatch.actual.display(db, Edition::LATEST)
+                            mismatch.expected.display(db, display_target),
+                            mismatch.actual.display(db, display_target)
                         );
                     }
                 }
@@ -843,12 +846,12 @@ impl flags::AnalysisStats {
                             start.col,
                             end.line + 1,
                             end.col,
-                            ty.display(db, Edition::LATEST)
+                            ty.display(db, display_target)
                         ));
                     } else {
                         bar.println(format!(
                             "unknown location: {}",
-                            ty.display(db, Edition::LATEST)
+                            ty.display(db, display_target)
                         ));
                     }
                 }
@@ -856,7 +859,7 @@ impl flags::AnalysisStats {
                     println!(
                         r#"{},type,"{}""#,
                         location_csv_pat(db, vfs, &sm(), pat_id),
-                        ty.display(db, Edition::LATEST)
+                        ty.display(db, display_target)
                     );
                 }
                 if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) {
@@ -870,15 +873,15 @@ impl flags::AnalysisStats {
                                 start.col,
                                 end.line + 1,
                                 end.col,
-                                mismatch.expected.display(db, Edition::LATEST),
-                                mismatch.actual.display(db, Edition::LATEST)
+                                mismatch.expected.display(db, display_target),
+                                mismatch.actual.display(db, display_target)
                             ));
                         } else {
                             bar.println(format!(
                                 "{}: Expected {}, got {}",
                                 name.display(db, Edition::LATEST),
-                                mismatch.expected.display(db, Edition::LATEST),
-                                mismatch.actual.display(db, Edition::LATEST)
+                                mismatch.expected.display(db, display_target),
+                                mismatch.actual.display(db, display_target)
                             ));
                         }
                     }
@@ -886,8 +889,8 @@ impl flags::AnalysisStats {
                         println!(
                             r#"{},mismatch,"{}","{}""#,
                             location_csv_pat(db, vfs, &sm(), pat_id),
-                            mismatch.expected.display(db, Edition::LATEST),
-                            mismatch.actual.display(db, Edition::LATEST)
+                            mismatch.expected.display(db, display_target),
+                            mismatch.actual.display(db, display_target)
                         );
                     }
                 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 713e28c87cb..45ac68339b3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -18,7 +18,7 @@ use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
     SnippetCap,
 };
-use itertools::Itertools;
+use itertools::{Either, Itertools};
 use paths::{Utf8Path, Utf8PathBuf};
 use project_model::{
     CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand,
@@ -589,6 +589,10 @@ config_data! {
         /// avoid checking unnecessary things.
         cargo_buildScripts_useRustcWrapper: bool = true,
         /// List of cfg options to enable with the given values.
+        ///
+        /// To enable a name without a value, use `"key"`.
+        /// To enable a name with a value, use `"key=value"`.
+        /// To disable, prefix the entry with a `!`.
         cargo_cfgs: Vec<String> = {
             vec!["debug_assertions".into(), "miri".into()]
         },
@@ -1980,27 +1984,35 @@ impl Config {
             rustc_source,
             extra_includes,
             cfg_overrides: project_model::CfgOverrides {
-                global: CfgDiff::new(
-                    self.cargo_cfgs(source_root)
-                        .iter()
-                        // parse any cfg setting formatted as key=value or just key (without value)
-                        .filter_map(|s| {
-                            let mut sp = s.splitn(2, "=");
-                            let key = sp.next();
-                            let val = sp.next();
-                            key.map(|key| (key, val))
-                        })
-                        .map(|(key, val)| match val {
-                            Some(val) => CfgAtom::KeyValue {
-                                key: Symbol::intern(key),
-                                value: Symbol::intern(val),
-                            },
-                            None => CfgAtom::Flag(Symbol::intern(key)),
-                        })
-                        .collect(),
-                    vec![],
-                )
-                .unwrap(),
+                global: {
+                    let (enabled, disabled): (Vec<_>, Vec<_>) =
+                        self.cargo_cfgs(source_root).iter().partition_map(|s| {
+                            s.strip_prefix("!").map_or(Either::Left(s), Either::Right)
+                        });
+                    CfgDiff::new(
+                        enabled
+                            .into_iter()
+                            // parse any cfg setting formatted as key=value or just key (without value)
+                            .map(|s| match s.split_once("=") {
+                                Some((key, val)) => CfgAtom::KeyValue {
+                                    key: Symbol::intern(key),
+                                    value: Symbol::intern(val),
+                                },
+                                None => CfgAtom::Flag(Symbol::intern(s)),
+                            })
+                            .collect(),
+                        disabled
+                            .into_iter()
+                            .map(|s| match s.split_once("=") {
+                                Some((key, val)) => CfgAtom::KeyValue {
+                                    key: Symbol::intern(key),
+                                    value: Symbol::intern(val),
+                                },
+                                None => CfgAtom::Flag(Symbol::intern(s)),
+                            })
+                            .collect(),
+                    )
+                },
                 selective: Default::default(),
             },
             wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(source_root),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 2309f94a742..7529e7c188f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -244,8 +244,14 @@ struct FlycheckActor {
     /// The receiver side of the channel mentioned above.
     command_receiver: Option<Receiver<CargoCheckMessage>>,
     diagnostics_cleared_for: FxHashSet<Arc<PackageId>>,
-    diagnostics_cleared_for_all: bool,
-    diagnostics_received: bool,
+    diagnostics_received: DiagnosticsReceived,
+}
+
+#[derive(PartialEq)]
+enum DiagnosticsReceived {
+    Yes,
+    No,
+    YesAndClearedForAll,
 }
 
 #[allow(clippy::large_enum_variant)]
@@ -276,8 +282,7 @@ impl FlycheckActor {
             command_handle: None,
             command_receiver: None,
             diagnostics_cleared_for: Default::default(),
-            diagnostics_cleared_for_all: false,
-            diagnostics_received: false,
+            diagnostics_received: DiagnosticsReceived::No,
         }
     }
 
@@ -354,7 +359,7 @@ impl FlycheckActor {
                             error
                         );
                     }
-                    if !self.diagnostics_received {
+                    if self.diagnostics_received == DiagnosticsReceived::No {
                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
                         // We finished without receiving any diagnostics.
                         // Clear everything for good measure
@@ -396,7 +401,7 @@ impl FlycheckActor {
                             package_id = package_id.as_ref().map(|it| &it.repr),
                             "diagnostic received"
                         );
-                        self.diagnostics_received = true;
+                        self.diagnostics_received = DiagnosticsReceived::Yes;
                         if let Some(package_id) = &package_id {
                             if self.diagnostics_cleared_for.insert(package_id.clone()) {
                                 tracing::trace!(
@@ -409,8 +414,10 @@ impl FlycheckActor {
                                     package_id: Some(package_id.clone()),
                                 });
                             }
-                        } else if !self.diagnostics_cleared_for_all {
-                            self.diagnostics_cleared_for_all = true;
+                        } else if self.diagnostics_received
+                            != DiagnosticsReceived::YesAndClearedForAll
+                        {
+                            self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll;
                             self.send(FlycheckMessage::ClearDiagnostics {
                                 id: self.id,
                                 package_id: None,
@@ -445,8 +452,7 @@ impl FlycheckActor {
 
     fn clear_diagnostics_state(&mut self) {
         self.diagnostics_cleared_for.clear();
-        self.diagnostics_cleared_for_all = false;
-        self.diagnostics_received = false;
+        self.diagnostics_received = DiagnosticsReceived::No;
     }
 
     /// Construct a `Command` object for checking the user's code. If the user
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 70105cda006..54670b67598 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -637,6 +637,25 @@ impl GlobalState {
             }
         });
     }
+
+    pub(crate) fn check_workspaces_msrv(&self) -> impl Iterator<Item = String> + '_ {
+        self.workspaces.iter().filter_map(|ws| {
+            if let Some(toolchain) = &ws.toolchain {
+                if *toolchain < crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION {
+                    return Some(format!(
+                        "Workspace `{}` is using an outdated toolchain version `{}` but \
+                        rust-analyzer only supports `{}` and higher.\n\
+                        Consider using the rust-analyzer rustup component for your toolchain or
+                        upgrade your toolchain to a supported version.\n\n",
+                        ws.manifest_or_root(),
+                        toolchain,
+                        crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION,
+                    ));
+                }
+            }
+            None
+        })
+    }
 }
 
 impl Drop for GlobalState {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index b91a5dbd416..68b2d6b6962 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -32,13 +32,13 @@ use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
-    completion_item_hash,
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
     diagnostics::convert_diagnostic,
     global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
     hack_recover_crate_name,
     line_index::LineEndings,
     lsp::{
+        completion_item_hash,
         ext::{
             InternalTestingFetchConfigOption, InternalTestingFetchConfigParams,
             InternalTestingFetchConfigResponse,
@@ -427,7 +427,12 @@ pub(crate) fn handle_on_enter(
         Some(it) => it,
     };
     let line_index = snap.file_line_index(position.file_id)?;
-    let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit);
+    let edit = to_proto::snippet_text_edit_vec(
+        &line_index,
+        true,
+        edit,
+        snap.config.change_annotation_support(),
+    );
     Ok(Some(edit))
 }
 
@@ -464,7 +469,12 @@ pub(crate) fn handle_on_type_formatting(
     let (_, (text_edit, snippet_edit)) = edit.source_file_edits.into_iter().next().unwrap();
     stdx::always!(snippet_edit.is_none(), "on type formatting shouldn't use structured snippets");
 
-    let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit);
+    let change = to_proto::snippet_text_edit_vec(
+        &line_index,
+        edit.is_snippet,
+        text_edit,
+        snap.config.change_annotation_support(),
+    );
     Ok(Some(change))
 }
 
@@ -2025,7 +2035,12 @@ pub(crate) fn handle_move_item(
     match snap.analysis.move_item(range, direction)? {
         Some(text_edit) => {
             let line_index = snap.file_line_index(file_id)?;
-            Ok(to_proto::snippet_text_edit_vec(&line_index, true, text_edit))
+            Ok(to_proto::snippet_text_edit_vec(
+                &line_index,
+                true,
+                text_edit,
+                snap.config.change_annotation_support(),
+            ))
         }
         None => Ok(vec![]),
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 27d6225cdb7..a0d6a0d6da6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -9,6 +9,15 @@
 //! The `cli` submodule implements some batch-processing analysis, primarily as
 //! a debugging aid.
 
+/// Any toolchain less than this version will likely not work with rust-analyzer built from this revision.
+pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version {
+    major: 1,
+    minor: 78,
+    patch: 0,
+    pre: semver::Prerelease::EMPTY,
+    build: semver::BuildMetadata::EMPTY,
+};
+
 pub mod cli;
 
 mod command;
@@ -47,10 +56,7 @@ use self::lsp::ext as lsp_ext;
 #[cfg(test)]
 mod integrated_benchmarks;
 
-use hir::Mutability;
-use ide::{CompletionItem, CompletionItemRefMode, CompletionRelevance};
 use serde::de::DeserializeOwned;
-use tenthash::TentHash;
 
 pub use crate::{
     lsp::capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph,
@@ -65,115 +71,6 @@ pub fn from_json<T: DeserializeOwned>(
         .map_err(|e| anyhow::format_err!("Failed to deserialize {what}: {e}; {json}"))
 }
 
-fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
-    fn hash_completion_relevance(hasher: &mut TentHash, relevance: &CompletionRelevance) {
-        use ide_completion::{
-            CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
-            CompletionRelevanceTypeMatch,
-        };
-
-        hasher.update([
-            u8::from(relevance.exact_name_match),
-            u8::from(relevance.is_local),
-            u8::from(relevance.is_name_already_imported),
-            u8::from(relevance.requires_import),
-            u8::from(relevance.is_private_editable),
-        ]);
-
-        match relevance.type_match {
-            None => hasher.update([0u8]),
-            Some(CompletionRelevanceTypeMatch::CouldUnify) => hasher.update([1u8]),
-            Some(CompletionRelevanceTypeMatch::Exact) => hasher.update([2u8]),
-        }
-
-        hasher.update([u8::from(relevance.trait_.is_some())]);
-        if let Some(trait_) = &relevance.trait_ {
-            hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
-        }
-
-        match relevance.postfix_match {
-            None => hasher.update([0u8]),
-            Some(CompletionRelevancePostfixMatch::NonExact) => hasher.update([1u8]),
-            Some(CompletionRelevancePostfixMatch::Exact) => hasher.update([2u8]),
-        }
-
-        hasher.update([u8::from(relevance.function.is_some())]);
-        if let Some(function) = &relevance.function {
-            hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
-            let discriminant: u8 = match function.return_type {
-                CompletionRelevanceReturnType::Other => 0,
-                CompletionRelevanceReturnType::DirectConstructor => 1,
-                CompletionRelevanceReturnType::Constructor => 2,
-                CompletionRelevanceReturnType::Builder => 3,
-            };
-            hasher.update([discriminant]);
-        }
-    }
-
-    let mut hasher = TentHash::new();
-    hasher.update([
-        u8::from(is_ref_completion),
-        u8::from(item.is_snippet),
-        u8::from(item.deprecated),
-        u8::from(item.trigger_call_info),
-    ]);
-
-    hasher.update(item.label.primary.len().to_ne_bytes());
-    hasher.update(&item.label.primary);
-
-    hasher.update([u8::from(item.label.detail_left.is_some())]);
-    if let Some(label_detail) = &item.label.detail_left {
-        hasher.update(label_detail.len().to_ne_bytes());
-        hasher.update(label_detail);
-    }
-
-    hasher.update([u8::from(item.label.detail_right.is_some())]);
-    if let Some(label_detail) = &item.label.detail_right {
-        hasher.update(label_detail.len().to_ne_bytes());
-        hasher.update(label_detail);
-    }
-
-    // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
-    // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
-    //
-    // Documentation hashing is skipped too, as it's a large blob to process,
-    // while not really making completion properties more unique as they are already.
-
-    let kind_tag = item.kind.tag();
-    hasher.update(kind_tag.len().to_ne_bytes());
-    hasher.update(kind_tag);
-
-    hasher.update(item.lookup.len().to_ne_bytes());
-    hasher.update(&item.lookup);
-
-    hasher.update([u8::from(item.detail.is_some())]);
-    if let Some(detail) = &item.detail {
-        hasher.update(detail.len().to_ne_bytes());
-        hasher.update(detail);
-    }
-
-    hash_completion_relevance(&mut hasher, &item.relevance);
-
-    hasher.update([u8::from(item.ref_match.is_some())]);
-    if let Some((ref_mode, text_size)) = &item.ref_match {
-        let discriminant = match ref_mode {
-            CompletionItemRefMode::Reference(Mutability::Shared) => 0u8,
-            CompletionItemRefMode::Reference(Mutability::Mut) => 1u8,
-            CompletionItemRefMode::Dereference => 2u8,
-        };
-        hasher.update([discriminant]);
-        hasher.update(u32::from(*text_size).to_ne_bytes());
-    }
-
-    hasher.update(item.import_to_add.len().to_ne_bytes());
-    for import_path in &item.import_to_add {
-        hasher.update(import_path.len().to_ne_bytes());
-        hasher.update(import_path);
-    }
-
-    hasher.finalize()
-}
-
 #[doc(hidden)]
 macro_rules! try_default_ {
     ($it:expr $(,)?) => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs
index 122ad20d65e..c7a5a95e66b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs
@@ -2,6 +2,10 @@
 
 use core::fmt;
 
+use hir::Mutability;
+use ide::{CompletionItem, CompletionItemRefMode, CompletionRelevance};
+use tenthash::TentHash;
+
 pub mod ext;
 
 pub(crate) mod capabilities;
@@ -29,3 +33,112 @@ impl fmt::Display for LspError {
 }
 
 impl std::error::Error for LspError {}
+
+pub(crate) fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
+    fn hash_completion_relevance(hasher: &mut TentHash, relevance: &CompletionRelevance) {
+        use ide_completion::{
+            CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
+            CompletionRelevanceTypeMatch,
+        };
+
+        hasher.update([
+            u8::from(relevance.exact_name_match),
+            u8::from(relevance.is_local),
+            u8::from(relevance.is_name_already_imported),
+            u8::from(relevance.requires_import),
+            u8::from(relevance.is_private_editable),
+        ]);
+
+        match relevance.type_match {
+            None => hasher.update([0u8]),
+            Some(CompletionRelevanceTypeMatch::CouldUnify) => hasher.update([1u8]),
+            Some(CompletionRelevanceTypeMatch::Exact) => hasher.update([2u8]),
+        }
+
+        hasher.update([u8::from(relevance.trait_.is_some())]);
+        if let Some(trait_) = &relevance.trait_ {
+            hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
+        }
+
+        match relevance.postfix_match {
+            None => hasher.update([0u8]),
+            Some(CompletionRelevancePostfixMatch::NonExact) => hasher.update([1u8]),
+            Some(CompletionRelevancePostfixMatch::Exact) => hasher.update([2u8]),
+        }
+
+        hasher.update([u8::from(relevance.function.is_some())]);
+        if let Some(function) = &relevance.function {
+            hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
+            let discriminant: u8 = match function.return_type {
+                CompletionRelevanceReturnType::Other => 0,
+                CompletionRelevanceReturnType::DirectConstructor => 1,
+                CompletionRelevanceReturnType::Constructor => 2,
+                CompletionRelevanceReturnType::Builder => 3,
+            };
+            hasher.update([discriminant]);
+        }
+    }
+
+    let mut hasher = TentHash::new();
+    hasher.update([
+        u8::from(is_ref_completion),
+        u8::from(item.is_snippet),
+        u8::from(item.deprecated),
+        u8::from(item.trigger_call_info),
+    ]);
+
+    hasher.update(item.label.primary.len().to_ne_bytes());
+    hasher.update(&item.label.primary);
+
+    hasher.update([u8::from(item.label.detail_left.is_some())]);
+    if let Some(label_detail) = &item.label.detail_left {
+        hasher.update(label_detail.len().to_ne_bytes());
+        hasher.update(label_detail);
+    }
+
+    hasher.update([u8::from(item.label.detail_right.is_some())]);
+    if let Some(label_detail) = &item.label.detail_right {
+        hasher.update(label_detail.len().to_ne_bytes());
+        hasher.update(label_detail);
+    }
+
+    // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
+    // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
+    //
+    // Documentation hashing is skipped too, as it's a large blob to process,
+    // while not really making completion properties more unique as they are already.
+
+    let kind_tag = item.kind.tag();
+    hasher.update(kind_tag.len().to_ne_bytes());
+    hasher.update(kind_tag);
+
+    hasher.update(item.lookup.len().to_ne_bytes());
+    hasher.update(&item.lookup);
+
+    hasher.update([u8::from(item.detail.is_some())]);
+    if let Some(detail) = &item.detail {
+        hasher.update(detail.len().to_ne_bytes());
+        hasher.update(detail);
+    }
+
+    hash_completion_relevance(&mut hasher, &item.relevance);
+
+    hasher.update([u8::from(item.ref_match.is_some())]);
+    if let Some((ref_mode, text_size)) = &item.ref_match {
+        let discriminant = match ref_mode {
+            CompletionItemRefMode::Reference(Mutability::Shared) => 0u8,
+            CompletionItemRefMode::Reference(Mutability::Mut) => 1u8,
+            CompletionItemRefMode::Dereference => 2u8,
+        };
+        hasher.update([discriminant]);
+        hasher.update(u32::from(*text_size).to_ne_bytes());
+    }
+
+    hasher.update(item.import_to_add.len().to_ne_bytes());
+    for import_path in &item.import_to_add {
+        hasher.update(import_path.len().to_ne_bytes());
+        hasher.update(import_path);
+    }
+
+    hasher.finalize()
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 446549c9070..6db7bcb1110 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -24,11 +24,11 @@ use serde_json::to_value;
 use vfs::AbsPath;
 
 use crate::{
-    completion_item_hash,
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
     lsp::{
+        completion_item_hash,
         ext::ShellRunnableArgs,
         semantic_tokens::{self, standard_fallback_type},
         utils::invalid_params_error,
@@ -200,7 +200,10 @@ pub(crate) fn snippet_text_edit(
     line_index: &LineIndex,
     is_snippet: bool,
     indel: Indel,
+    client_supports_annotations: bool,
 ) -> lsp_ext::SnippetTextEdit {
+    let annotation_id =
+        indel.annotation.filter(|_| client_supports_annotations).map(|it| it.to_string());
     let text_edit = text_edit(line_index, indel);
     let insert_text_format =
         if is_snippet { Some(lsp_types::InsertTextFormat::SNIPPET) } else { None };
@@ -208,7 +211,7 @@ pub(crate) fn snippet_text_edit(
         range: text_edit.range,
         new_text: text_edit.new_text,
         insert_text_format,
-        annotation_id: None,
+        annotation_id,
     }
 }
 
@@ -223,10 +226,13 @@ pub(crate) fn snippet_text_edit_vec(
     line_index: &LineIndex,
     is_snippet: bool,
     text_edit: TextEdit,
+    clients_support_annotations: bool,
 ) -> Vec<lsp_ext::SnippetTextEdit> {
     text_edit
         .into_iter()
-        .map(|indel| self::snippet_text_edit(line_index, is_snippet, indel))
+        .map(|indel| {
+            self::snippet_text_edit(line_index, is_snippet, indel, clients_support_annotations)
+        })
         .collect()
 }
 
@@ -1072,6 +1078,7 @@ fn merge_text_and_snippet_edits(
     line_index: &LineIndex,
     edit: TextEdit,
     snippet_edit: SnippetEdit,
+    client_supports_annotations: bool,
 ) -> Vec<SnippetTextEdit> {
     let mut edits: Vec<SnippetTextEdit> = vec![];
     let mut snippets = snippet_edit.into_edit_ranges().into_iter().peekable();
@@ -1120,7 +1127,12 @@ fn merge_text_and_snippet_edits(
             edits.push(snippet_text_edit(
                 line_index,
                 true,
-                Indel { insert: format!("${snippet_index}"), delete: snippet_range },
+                Indel {
+                    insert: format!("${snippet_index}"),
+                    delete: snippet_range,
+                    annotation: None,
+                },
+                client_supports_annotations,
             ))
         }
 
@@ -1178,12 +1190,22 @@ fn merge_text_and_snippet_edits(
             edits.push(snippet_text_edit(
                 line_index,
                 true,
-                Indel { insert: new_text, delete: current_indel.delete },
+                Indel {
+                    insert: new_text,
+                    delete: current_indel.delete,
+                    annotation: current_indel.annotation,
+                },
+                client_supports_annotations,
             ))
         } else {
             // snippet edit was beyond the current one
             // since it wasn't consumed, it's available for the next pass
-            edits.push(snippet_text_edit(line_index, false, current_indel));
+            edits.push(snippet_text_edit(
+                line_index,
+                false,
+                current_indel,
+                client_supports_annotations,
+            ));
         }
 
         // update the final source -> initial source mapping offset
@@ -1208,7 +1230,8 @@ fn merge_text_and_snippet_edits(
         snippet_text_edit(
             line_index,
             true,
-            Indel { insert: format!("${snippet_index}"), delete: snippet_range },
+            Indel { insert: format!("${snippet_index}"), delete: snippet_range, annotation: None },
+            client_supports_annotations,
         )
     }));
 
@@ -1224,10 +1247,13 @@ pub(crate) fn snippet_text_document_edit(
 ) -> Cancellable<lsp_ext::SnippetTextDocumentEdit> {
     let text_document = optional_versioned_text_document_identifier(snap, file_id);
     let line_index = snap.file_line_index(file_id)?;
+    let client_supports_annotations = snap.config.change_annotation_support();
     let mut edits = if let Some(snippet_edit) = snippet_edit {
-        merge_text_and_snippet_edits(&line_index, edit, snippet_edit)
+        merge_text_and_snippet_edits(&line_index, edit, snippet_edit, client_supports_annotations)
     } else {
-        edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect()
+        edit.into_iter()
+            .map(|it| snippet_text_edit(&line_index, is_snippet, it, client_supports_annotations))
+            .collect()
     };
 
     if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() {
@@ -1348,6 +1374,16 @@ pub(crate) fn snippet_workspace_edit(
                     )),
                 },
             ))
+            .chain(source_change.annotations.into_iter().map(|(id, annotation)| {
+                (
+                    id.to_string(),
+                    lsp_types::ChangeAnnotation {
+                        label: annotation.label,
+                        description: annotation.description,
+                        needs_confirmation: Some(annotation.needs_confirmation),
+                    },
+                )
+            }))
             .collect(),
         )
     }
@@ -2023,7 +2059,7 @@ fn bar(_: usize) {}
             encoding: PositionEncoding::Utf8,
         };
 
-        let res = merge_text_and_snippet_edits(&line_index, edit, snippets);
+        let res = merge_text_and_snippet_edits(&line_index, edit, snippets, true);
 
         // Ensure that none of the ranges overlap
         {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 56dcad0eb18..dffaa88240b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -178,6 +178,11 @@ impl GlobalState {
         }
 
         if !self.workspaces.is_empty() {
+            self.check_workspaces_msrv().for_each(|e| {
+                status.health |= lsp_ext::Health::Warning;
+                format_to!(message, "{e}");
+            });
+
             let proc_macro_clients =
                 self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
 
@@ -513,6 +518,11 @@ impl GlobalState {
             // we don't care about build-script results, they are stale.
             // FIXME: can we abort the build scripts here if they are already running?
             self.workspaces = Arc::new(workspaces);
+            self.check_workspaces_msrv().for_each(|message| {
+                self.send_notification::<lsp_types::notification::ShowMessage>(
+                    lsp_types::ShowMessageParams { typ: lsp_types::MessageType::WARNING, message },
+                );
+            });
 
             if self.config.run_build_scripts(None) {
                 self.build_deps_changed = false;
diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
index 19801c49e43..a59a3270c9d 100644
--- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
@@ -12,7 +12,7 @@ use syntax::{
     SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
 };
-use tt::{buffer::Cursor, token_to_literal};
+use tt::{buffer::Cursor, token_to_literal, Punct};
 
 pub mod prettify_macro_expansion;
 mod to_parser_input;
@@ -217,8 +217,39 @@ where
         tt::TopSubtreeBuilder::new(tt::Delimiter::invisible_spanned(conv.call_site()));
 
     while let Some((token, abs_range)) = conv.bump() {
-        let delimiter = builder.expected_delimiter().map(|it| it.kind);
         let tt = match token.as_leaf() {
+            // These delimiters are not actually valid punctuation, but we produce them in syntax fixup.
+            // So we need to handle them specially here.
+            Some(&tt::Leaf::Punct(Punct {
+                char: char @ ('(' | ')' | '{' | '}' | '[' | ']'),
+                span,
+                spacing: _,
+            })) => {
+                let found_expected_delimiter =
+                    builder.expected_delimiters().enumerate().find(|(_, delim)| match delim.kind {
+                        tt::DelimiterKind::Parenthesis => char == ')',
+                        tt::DelimiterKind::Brace => char == '}',
+                        tt::DelimiterKind::Bracket => char == ']',
+                        tt::DelimiterKind::Invisible => false,
+                    });
+                if let Some((idx, _)) = found_expected_delimiter {
+                    for _ in 0..=idx {
+                        builder.close(span);
+                    }
+                    continue;
+                }
+
+                let delim = match char {
+                    '(' => tt::DelimiterKind::Parenthesis,
+                    '{' => tt::DelimiterKind::Brace,
+                    '[' => tt::DelimiterKind::Bracket,
+                    _ => panic!("unmatched closing delimiter from syntax fixup"),
+                };
+
+                // Start a new subtree
+                builder.open(delim, span);
+                continue;
+            }
             Some(leaf) => leaf.clone(),
             None => match token.kind(conv) {
                 // Desugar doc comments into doc attributes
@@ -228,17 +259,24 @@ where
                     continue;
                 }
                 kind if kind.is_punct() && kind != UNDERSCORE => {
-                    let expected = match delimiter {
-                        Some(tt::DelimiterKind::Parenthesis) => Some(T![')']),
-                        Some(tt::DelimiterKind::Brace) => Some(T!['}']),
-                        Some(tt::DelimiterKind::Bracket) => Some(T![']']),
-                        Some(tt::DelimiterKind::Invisible) | None => None,
-                    };
+                    let found_expected_delimiter =
+                        builder.expected_delimiters().enumerate().find(|(_, delim)| {
+                            match delim.kind {
+                                tt::DelimiterKind::Parenthesis => kind == T![')'],
+                                tt::DelimiterKind::Brace => kind == T!['}'],
+                                tt::DelimiterKind::Bracket => kind == T![']'],
+                                tt::DelimiterKind::Invisible => false,
+                            }
+                        });
 
                     // Current token is a closing delimiter that we expect, fix up the closing span
-                    // and end the subtree here
-                    if matches!(expected, Some(expected) if expected == kind) {
-                        builder.close(conv.span_for(abs_range));
+                    // and end the subtree here.
+                    // We also close any open inner subtrees that might be missing their delimiter.
+                    if let Some((idx, _)) = found_expected_delimiter {
+                        for _ in 0..=idx {
+                            // FIXME: record an error somewhere if we're closing more than one tree here?
+                            builder.close(conv.span_for(abs_range));
+                        }
                         continue;
                     }
 
@@ -262,6 +300,7 @@ where
                     let Some(char) = token.to_char(conv) else {
                         panic!("Token from lexer must be single char: token = {token:#?}")
                     };
+                    // FIXME: this might still be an unmatched closing delimiter? Maybe we should assert here
                     tt::Leaf::from(tt::Punct { char, spacing, span: conv.span_for(abs_range) })
                 }
                 kind => {
@@ -317,11 +356,10 @@ where
         builder.push(tt);
     }
 
-    // If we get here, we've consumed all input tokens.
-    // We might have more than one subtree in the stack, if the delimiters are improperly balanced.
-    // Merge them so we're left with one.
-    builder.flatten_unclosed_subtrees();
-
+    while builder.expected_delimiters().next().is_some() {
+        // FIXME: record an error somewhere?
+        builder.close(conv.call_site());
+    }
     builder.build_skip_top_subtree()
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 88d7beb897e..70a91af6c47 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -279,6 +279,11 @@ Adt =
 | Struct
 | Union
 
+VariantDef =
+  Struct
+| Union
+| Variant
+
 Const =
   Attr* Visibility?
   'default'?
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 58c76a456ab..ebee5e9af2c 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -2447,6 +2447,17 @@ pub enum UseBoundGenericArg {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum VariantDef {
+    Struct(Struct),
+    Union(Union),
+    Variant(Variant),
+}
+impl ast::HasAttrs for VariantDef {}
+impl ast::HasDocComments for VariantDef {}
+impl ast::HasName for VariantDef {}
+impl ast::HasVisibility for VariantDef {}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AnyHasArgList {
     pub(crate) syntax: SyntaxNode,
 }
@@ -6738,6 +6749,40 @@ impl AstNode for UseBoundGenericArg {
         }
     }
 }
+impl From<Struct> for VariantDef {
+    #[inline]
+    fn from(node: Struct) -> VariantDef { VariantDef::Struct(node) }
+}
+impl From<Union> for VariantDef {
+    #[inline]
+    fn from(node: Union) -> VariantDef { VariantDef::Union(node) }
+}
+impl From<Variant> for VariantDef {
+    #[inline]
+    fn from(node: Variant) -> VariantDef { VariantDef::Variant(node) }
+}
+impl AstNode for VariantDef {
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, STRUCT | UNION | VARIANT) }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            STRUCT => VariantDef::Struct(Struct { syntax }),
+            UNION => VariantDef::Union(Union { syntax }),
+            VARIANT => VariantDef::Variant(Variant { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            VariantDef::Struct(it) => &it.syntax,
+            VariantDef::Union(it) => &it.syntax,
+            VariantDef::Variant(it) => &it.syntax,
+        }
+    }
+}
 impl AnyHasArgList {
     #[inline]
     pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
@@ -7753,6 +7798,11 @@ impl std::fmt::Display for UseBoundGenericArg {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for VariantDef {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for Abi {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
index 0c4da762992..4f0e2cad174 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
@@ -1,5 +1,7 @@
 //! Precedence representation.
 
+use stdx::always;
+
 use crate::{
     ast::{self, BinaryOp, Expr, HasArgList, RangeItem},
     match_ast, AstNode, SyntaxNode,
@@ -140,6 +142,22 @@ pub fn precedence(expr: &ast::Expr) -> ExprPrecedence {
     }
 }
 
+fn check_ancestry(ancestor: &SyntaxNode, descendent: &SyntaxNode) -> bool {
+    let bail = || always!(false, "{} is not an ancestor of {}", ancestor, descendent);
+
+    if !ancestor.text_range().contains_range(descendent.text_range()) {
+        return bail();
+    }
+
+    for anc in descendent.ancestors() {
+        if anc == *ancestor {
+            return true;
+        }
+    }
+
+    bail()
+}
+
 impl Expr {
     pub fn precedence(&self) -> ExprPrecedence {
         precedence(self)
@@ -153,9 +171,19 @@ impl Expr {
 
     /// Returns `true` if `self` would need to be wrapped in parentheses given that its parent is `parent`.
     pub fn needs_parens_in(&self, parent: &SyntaxNode) -> bool {
+        self.needs_parens_in_place_of(parent, self.syntax())
+    }
+
+    /// Returns `true` if `self` would need to be wrapped in parentheses if it replaces `place_of`
+    /// given that `place_of`'s parent is `parent`.
+    pub fn needs_parens_in_place_of(&self, parent: &SyntaxNode, place_of: &SyntaxNode) -> bool {
+        if !check_ancestry(parent, place_of) {
+            return false;
+        }
+
         match_ast! {
             match parent {
-                ast::Expr(e) => self.needs_parens_in_expr(&e),
+                ast::Expr(e) => self.needs_parens_in_expr(&e, place_of),
                 ast::Stmt(e) => self.needs_parens_in_stmt(Some(&e)),
                 ast::StmtList(_) => self.needs_parens_in_stmt(None),
                 ast::ArgList(_) => false,
@@ -165,7 +193,7 @@ impl Expr {
         }
     }
 
-    fn needs_parens_in_expr(&self, parent: &Expr) -> bool {
+    fn needs_parens_in_expr(&self, parent: &Expr, place_of: &SyntaxNode) -> bool {
         // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union
         // (e.g. `(a.f)()`).
         let is_parent_call_expr = matches!(parent, ast::Expr::CallExpr(_));
@@ -199,13 +227,17 @@ impl Expr {
 
         if self.is_paren_like()
             || parent.is_paren_like()
-            || self.is_prefix() && (parent.is_prefix() || !self.is_ordered_before(parent))
-            || self.is_postfix() && (parent.is_postfix() || self.is_ordered_before(parent))
+            || self.is_prefix()
+                && (parent.is_prefix()
+                    || !self.is_ordered_before_parent_in_place_of(parent, place_of))
+            || self.is_postfix()
+                && (parent.is_postfix()
+                    || self.is_ordered_before_parent_in_place_of(parent, place_of))
         {
             return false;
         }
 
-        let (left, right, inv) = match self.is_ordered_before(parent) {
+        let (left, right, inv) = match self.is_ordered_before_parent_in_place_of(parent, place_of) {
             true => (self, parent, false),
             false => (parent, self, true),
         };
@@ -413,13 +445,28 @@ impl Expr {
         }
     }
 
-    fn is_ordered_before(&self, other: &Expr) -> bool {
+    fn is_ordered_before_parent_in_place_of(&self, parent: &Expr, place_of: &SyntaxNode) -> bool {
+        use rowan::TextSize;
         use Expr::*;
 
-        return order(self) < order(other);
+        let self_range = self.syntax().text_range();
+        let place_of_range = place_of.text_range();
+
+        let self_order_adjusted = order(self) - self_range.start() + place_of_range.start();
+
+        let parent_order = order(parent);
+        let parent_order_adjusted = if parent_order <= place_of_range.start() {
+            parent_order
+        } else if parent_order >= place_of_range.end() {
+            parent_order - place_of_range.len() + self_range.len()
+        } else {
+            return false;
+        };
+
+        return self_order_adjusted < parent_order_adjusted;
 
         /// Returns text range that can be used to compare two expression for order (which goes first).
-        fn order(this: &Expr) -> rowan::TextSize {
+        fn order(this: &Expr) -> TextSize {
             // For non-paren-like operators: get the operator itself
             let token = match this {
                 RangeExpr(e) => e.op_token(),
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 85393ca5b4c..44f13041c24 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -783,6 +783,27 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn record_expr_field(
+        &self,
+        name: ast::NameRef,
+        expr: Option<ast::Expr>,
+    ) -> ast::RecordExprField {
+        let ast = make::record_expr_field(name.clone(), expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+
+            builder.map_node(name.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
+            if let Some(expr) = expr {
+                builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            }
+
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn record_field_list(
         &self,
         fields: impl IntoIterator<Item = ast::RecordField>,
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
index 13d352d3c69..85eefac734b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
@@ -37,6 +37,7 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
                 ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors),
                 ast::MacroRules(it) => validate_macro_rules(it, errors),
                 ast::LetExpr(it) => validate_let_expr(it, errors),
+                ast::ImplTraitType(it) => validate_impl_object_ty(it, errors),
                 _ => (),
             }
         }
@@ -340,17 +341,34 @@ fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<Synt
 
 fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
     let tbl = ty.type_bound_list()?;
-
-    if tbl.bounds().count() > 1 {
-        let dyn_token = ty.dyn_token()?;
-        let potential_parenthesis =
-            algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
-        let kind = potential_parenthesis.kind();
-        if !matches!(kind, T!['('] | T![<] | T![=]) {
-            return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
+    let bounds_count = tbl.bounds().count();
+
+    match bounds_count {
+        0 => Some(SyntaxError::new(
+            "At least one trait is required for an object type",
+            ty.syntax().text_range(),
+        )),
+        _ if bounds_count > 1 => {
+            let dyn_token = ty.dyn_token()?;
+            let preceding_token =
+                algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
+
+            if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
+                return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
+            }
+            None
         }
+        _ => None,
+    }
+}
+
+fn validate_impl_object_ty(ty: ast::ImplTraitType, errors: &mut Vec<SyntaxError>) {
+    if ty.type_bound_list().map_or(0, |tbl| tbl.bounds().count()) == 0 {
+        errors.push(SyntaxError::new(
+            "At least one trait must be specified",
+            ty.syntax().text_range(),
+        ));
     }
-    None
 }
 
 fn validate_macro_rules(mac: ast::MacroRules, errors: &mut Vec<SyntaxError>) {
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rast
new file mode 100644
index 00000000000..b31af5fbc6a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rast
@@ -0,0 +1,25 @@
+SOURCE_FILE@0..16
+  FN@0..16
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..4
+      IDENT@3..4 "f"
+    PARAM_LIST@4..13
+      L_PAREN@4..5 "("
+      PARAM@5..12
+        WILDCARD_PAT@5..6
+          UNDERSCORE@5..6 "_"
+        COLON@6..7 ":"
+        WHITESPACE@7..8 " "
+        REF_TYPE@8..12
+          AMP@8..9 "&"
+          DYN_TRAIT_TYPE@9..12
+            DYN_KW@9..12 "dyn"
+            TYPE_BOUND_LIST@12..12
+      R_PAREN@12..13 ")"
+    WHITESPACE@13..14 " "
+    BLOCK_EXPR@14..16
+      STMT_LIST@14..16
+        L_CURLY@14..15 "{"
+        R_CURLY@15..16 "}"
+error 9..12: At least one trait is required for an object type
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rs
new file mode 100644
index 00000000000..2fdbb42846b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rs
@@ -0,0 +1 @@
+fn f(_: &dyn) {}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast
new file mode 100644
index 00000000000..2db07ae12a9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast
@@ -0,0 +1,23 @@
+SOURCE_FILE@0..16
+  FN@0..16
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..4
+      IDENT@3..4 "f"
+    PARAM_LIST@4..13
+      L_PAREN@4..5 "("
+      PARAM@5..12
+        WILDCARD_PAT@5..6
+          UNDERSCORE@5..6 "_"
+        COLON@6..7 ":"
+        WHITESPACE@7..8 " "
+        IMPL_TRAIT_TYPE@8..12
+          IMPL_KW@8..12 "impl"
+          TYPE_BOUND_LIST@12..12
+      R_PAREN@12..13 ")"
+    WHITESPACE@13..14 " "
+    BLOCK_EXPR@14..16
+      STMT_LIST@14..16
+        L_CURLY@14..15 "{"
+        R_CURLY@15..16 "}"
+error 8..12: At least one trait must be specified
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rs
new file mode 100644
index 00000000000..61706d9e412
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rs
@@ -0,0 +1 @@
+fn f(_: impl) {}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
new file mode 100644
index 00000000000..dbe6535ac66
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
@@ -0,0 +1,25 @@
+SOURCE_FILE@0..17
+  FN@0..17
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..4
+      IDENT@3..4 "f"
+    PARAM_LIST@4..14
+      L_PAREN@4..5 "("
+      PARAM@5..13
+        WILDCARD_PAT@5..6
+          UNDERSCORE@5..6 "_"
+        COLON@6..7 ":"
+        WHITESPACE@7..8 " "
+        REF_TYPE@8..13
+          AMP@8..9 "&"
+          IMPL_TRAIT_TYPE@9..13
+            IMPL_KW@9..13 "impl"
+            TYPE_BOUND_LIST@13..13
+      R_PAREN@13..14 ")"
+    WHITESPACE@14..15 " "
+    BLOCK_EXPR@15..17
+      STMT_LIST@15..17
+        L_CURLY@15..16 "{"
+        R_CURLY@16..17 "}"
+error 9..13: At least one trait must be specified
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rs
new file mode 100644
index 00000000000..0b440b4c5af
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rs
@@ -0,0 +1 @@
+fn f(_: &impl) {}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 202afebde70..bf53e58d70c 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -1825,7 +1825,7 @@ macro_rules! impl_int {
     ($($t:ty)*) => {
         $(
             impl $t {
-                pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+                pub const fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
                     unsafe { mem::transmute(bytes) }
                 }
             }
@@ -1874,6 +1874,7 @@ pub mod prelude {
             marker::Sized,                           // :sized
             marker::Sync,                            // :sync
             mem::drop,                               // :drop
+            mem::size_of,                            // :size_of
             ops::Drop,                               // :drop
             ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}, // :async_fn
             ops::{Fn, FnMut, FnOnce},                // :fn
@@ -1895,6 +1896,10 @@ pub mod prelude {
     pub mod rust_2021 {
         pub use super::v1::*;
     }
+
+    pub mod rust_2024 {
+        pub use super::v1::*;
+    }
 }
 
 #[prelude_import]
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index 7705ba876e1..1cfead54f19 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -243,8 +243,8 @@ impl<S: Copy> TopSubtreeBuilder<S> {
         self.token_trees.extend(tt.0.iter().cloned());
     }
 
-    pub fn expected_delimiter(&self) -> Option<&Delimiter<S>> {
-        self.unclosed_subtree_indices.last().map(|&subtree_idx| {
+    pub fn expected_delimiters(&self) -> impl Iterator<Item = &Delimiter<S>> {
+        self.unclosed_subtree_indices.iter().rev().map(|&subtree_idx| {
             let TokenTree::Subtree(subtree) = &self.token_trees[subtree_idx] else {
                 unreachable!("unclosed token tree is always a subtree")
             };
@@ -252,28 +252,6 @@ impl<S: Copy> TopSubtreeBuilder<S> {
         })
     }
 
-    /// Converts unclosed subtree to a punct of their open delimiter.
-    // FIXME: This is incorrect to do, delimiters can never be puncts. See #18244.
-    pub fn flatten_unclosed_subtrees(&mut self) {
-        for &subtree_idx in &self.unclosed_subtree_indices {
-            let TokenTree::Subtree(subtree) = &self.token_trees[subtree_idx] else {
-                unreachable!("unclosed token tree is always a subtree")
-            };
-            let char = match subtree.delimiter.kind {
-                DelimiterKind::Parenthesis => '(',
-                DelimiterKind::Brace => '{',
-                DelimiterKind::Bracket => '[',
-                DelimiterKind::Invisible => '$',
-            };
-            self.token_trees[subtree_idx] = TokenTree::Leaf(Leaf::Punct(Punct {
-                char,
-                spacing: Spacing::Alone,
-                span: subtree.delimiter.open,
-            }));
-        }
-        self.unclosed_subtree_indices.clear();
-    }
-
     /// Builds, and remove the top subtree if it has only one subtree child.
     pub fn build_skip_top_subtree(mut self) -> TopSubtree<S> {
         let top_tts = TokenTreesView::new(&self.token_trees[1..]);
@@ -731,9 +709,9 @@ fn print_debug_subtree<S: fmt::Debug>(
     };
 
     write!(f, "{align}SUBTREE {delim} ",)?;
-    fmt::Debug::fmt(&open, f)?;
+    write!(f, "{:#?}", open)?;
     write!(f, " ")?;
-    fmt::Debug::fmt(&close, f)?;
+    write!(f, "{:#?}", close)?;
     for child in iter {
         writeln!(f)?;
         print_debug_token(f, level + 1, child)?;
diff --git a/src/tools/rust-analyzer/docs/book/src/assists_generated.md b/src/tools/rust-analyzer/docs/book/src/assists_generated.md
index c2063df5068..9a801851792 100644
--- a/src/tools/rust-analyzer/docs/book/src/assists_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/assists_generated.md
@@ -28,6 +28,32 @@ fn foo(n: i32) -> i32 {
 ```
 
 
+### `add_explicit_enum_discriminant`
+**Source:**  [add_explicit_enum_discriminant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs#L11) 
+
+Adds explicit discriminant to all enum variants.
+
+#### Before
+```rust
+enum TheEnum┃ {
+    Foo,
+    Bar,
+    Baz = 42,
+    Quux,
+}
+```
+
+#### After
+```rust
+enum TheEnum {
+    Foo = 0,
+    Bar = 1,
+    Baz = 42,
+    Quux = 43,
+}
+```
+
+
 ### `add_explicit_type`
 **Source:**  [add_explicit_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_explicit_type.rs#L7) 
 
@@ -280,7 +306,7 @@ fn main() {
 
 
 ### `apply_demorgan_iterator`
-**Source:**  [apply_demorgan.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/apply_demorgan.rs#L154) 
+**Source:**  [apply_demorgan.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/apply_demorgan.rs#L156) 
 
 Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) to
 `Iterator::all` and `Iterator::any`.
@@ -350,40 +376,6 @@ fn some_function(x: i32) {
 ```
 
 
-### `bool_to_enum`
-**Source:**  [bool_to_enum.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/bool_to_enum.rs#L29) 
-
-This converts boolean local variables, fields, constants, and statics into a new
-enum with two variants `Bool::True` and `Bool::False`, as well as replacing
-all assignments with the variants and replacing all usages with `== Bool::True` or
-`== Bool::False`.
-
-#### Before
-```rust
-fn main() {
-    let ┃bool = true;
-
-    if bool {
-        println!("foo");
-    }
-}
-```
-
-#### After
-```rust
-#[derive(PartialEq, Eq)]
-enum Bool { True, False }
-
-fn main() {
-    let bool = Bool::True;
-
-    if bool == Bool::True {
-        println!("foo");
-    }
-}
-```
-
-
 ### `change_visibility`
 **Source:**  [change_visibility.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/change_visibility.rs#L13) 
 
@@ -442,8 +434,42 @@ fn main() {
 ```
 
 
+### `convert_bool_to_enum`
+**Source:**  [convert_bool_to_enum.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_bool_to_enum.rs#L29) 
+
+This converts boolean local variables, fields, constants, and statics into a new
+enum with two variants `Bool::True` and `Bool::False`, as well as replacing
+all assignments with the variants and replacing all usages with `== Bool::True` or
+`== Bool::False`.
+
+#### Before
+```rust
+fn main() {
+    let ┃bool = true;
+
+    if bool {
+        println!("foo");
+    }
+}
+```
+
+#### After
+```rust
+#[derive(PartialEq, Eq)]
+enum Bool { True, False }
+
+fn main() {
+    let bool = Bool::True;
+
+    if bool == Bool::True {
+        println!("foo");
+    }
+}
+```
+
+
 ### `convert_closure_to_fn`
-**Source:**  [convert_closure_to_fn.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_closure_to_fn.rs#L27) 
+**Source:**  [convert_closure_to_fn.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_closure_to_fn.rs#L25) 
 
 This converts a closure to a freestanding function, changing all captures to parameters.
 
@@ -1043,28 +1069,50 @@ pub use foo::{Bar, Baz};
 ```
 
 
-### `explicit_enum_discriminant`
-**Source:**  [explicit_enum_discriminant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs#L11) 
+### `expand_record_rest_pattern`
+**Source:**  [expand_rest_pattern.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/expand_rest_pattern.rs#L26) 
 
-Adds explicit discriminant to all enum variants.
+Fills fields by replacing rest pattern in record patterns.
 
 #### Before
 ```rust
-enum TheEnum┃ {
-    Foo,
-    Bar,
-    Baz = 42,
-    Quux,
+struct Bar { y: Y, z: Z }
+
+fn foo(bar: Bar) {
+    let Bar { ..┃ } = bar;
 }
 ```
 
 #### After
 ```rust
-enum TheEnum {
-    Foo = 0,
-    Bar = 1,
-    Baz = 42,
-    Quux = 43,
+struct Bar { y: Y, z: Z }
+
+fn foo(bar: Bar) {
+    let Bar { y, z  } = bar;
+}
+```
+
+
+### `expand_tuple_struct_rest_pattern`
+**Source:**  [expand_rest_pattern.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/expand_rest_pattern.rs#L82) 
+
+Fills fields by replacing rest pattern in tuple struct patterns.
+
+#### Before
+```rust
+struct Bar(Y, Z);
+
+fn foo(bar: Bar) {
+    let Bar(..┃) = bar;
+}
+```
+
+#### After
+```rust
+struct Bar(Y, Z);
+
+fn foo(bar: Bar) {
+    let Bar(_0, _1) = bar;
 }
 ```
 
@@ -1255,30 +1303,6 @@ fn main() {
 ```
 
 
-### `fill_record_pattern_fields`
-**Source:**  [fill_record_pattern_fields.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs#L8) 
-
-Fills fields by replacing rest pattern in record patterns.
-
-#### Before
-```rust
-struct Bar { y: Y, z: Z }
-
-fn foo(bar: Bar) {
-    let Bar { ..┃ } = bar;
-}
-```
-
-#### After
-```rust
-struct Bar { y: Y, z: Z }
-
-fn foo(bar: Bar) {
-    let Bar { y, z  } = bar;
-}
-```
-
-
 ### `fix_visibility`
 **Source:**  [fix_visibility.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/fix_visibility.rs#L14) 
 
@@ -1348,7 +1372,7 @@ fn main() {
 ### `flip_or_pattern`
 **Source:**  [flip_or_pattern.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/flip_or_pattern.rs#L9) 
 
-Flips two trait bounds.
+Flips two patterns in an or-pattern.
 
 #### Before
 ```rust
@@ -2278,7 +2302,7 @@ fn bar() {
 
 
 ### `inline_local_variable`
-**Source:**  [inline_local_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_local_variable.rs#L21) 
+**Source:**  [inline_local_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_local_variable.rs#L17) 
 
 Inlines a local variable.
 
@@ -2423,22 +2447,6 @@ fn main() -> () {
 ```
 
 
-### `introduce_named_generic`
-**Source:**  [introduce_named_generic.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_generic.rs#L7) 
-
-Replaces `impl Trait` function argument with the named generic.
-
-#### Before
-```rust
-fn foo(bar: ┃impl Bar) {}
-```
-
-#### After
-```rust
-fn foo<┃B: Bar>(bar: B) {}
-```
-
-
 ### `introduce_named_lifetime`
 **Source:**  [introduce_named_lifetime.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_lifetime.rs#L13) 
 
@@ -2467,6 +2475,22 @@ impl<'a> Cursor<'a> {
 ```
 
 
+### `introduce_named_type_parameter`
+**Source:**  [introduce_named_type_parameter.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs#L7) 
+
+Replaces `impl Trait` function argument with the named generic.
+
+#### Before
+```rust
+fn foo(bar: ┃impl Bar) {}
+```
+
+#### After
+```rust
+fn foo<┃B: Bar>(bar: B) {}
+```
+
+
 ### `invert_if`
 **Source:**  [invert_if.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/invert_if.rs#L13) 
 
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 1cbe51836f4..0a612d20b9c 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -102,6 +102,10 @@ Default:
 
  List of cfg options to enable with the given values.
 
+To enable a name without a value, use `"key"`.
+To enable a name with a value, use `"key=value"`.
+To disable, prefix the entry with a `!`.
+
 
  **rust-analyzer.cargo.extraArgs** (default: [])
 
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 587ae92520b..9df41c7487c 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -825,7 +825,7 @@
                 "title": "cargo",
                 "properties": {
                     "rust-analyzer.cargo.cfgs": {
-                        "markdownDescription": "List of cfg options to enable with the given values.",
+                        "markdownDescription": "List of cfg options to enable with the given values.\n\nTo enable a name without a value, use `\"key\"`.\nTo enable a name with a value, use `\"key=value\"`.\nTo disable, prefix the entry with a `!`.",
                         "default": [
                             "debug_assertions",
                             "miri"
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 2ae32913452..896b3c10cbf 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -27,6 +27,7 @@ export class Config {
         "server",
         "files",
         "cfg",
+        "showSyntaxTree",
     ].map((opt) => `${this.rootSection}.${opt}`);
 
     private readonly requiresWindowReloadOpts = ["testExplorer"].map(
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index ac73f2ae6bf..37a2ee23691 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -5,6 +5,7 @@ import * as ra from "./lsp_ext";
 import { Config, prepareVSCodeConfig } from "./config";
 import { createClient } from "./client";
 import {
+    isCargoTomlEditor,
     isDocumentInWorkspace,
     isRustDocument,
     isRustEditor,
@@ -429,6 +430,11 @@ export class Ctx implements RustAnalyzerExtensionApi {
         return editor && isRustEditor(editor) ? editor : undefined;
     }
 
+    get activeCargoTomlEditor(): RustEditor | undefined {
+        const editor = vscode.window.activeTextEditor;
+        return editor && isCargoTomlEditor(editor) ? editor : undefined;
+    }
+
     get extensionPath(): string {
         return this.extCtx.extensionPath;
     }
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index f71ab7ffbd8..40027cc7c85 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -7,7 +7,7 @@ import type { CtxInit } from "./ctx";
 import { makeDebugConfig } from "./debug";
 import type { Config } from "./config";
 import type { LanguageClient } from "vscode-languageclient/node";
-import { unwrapUndefinable, type RustEditor } from "./util";
+import { log, unwrapUndefinable, type RustEditor } from "./util";
 
 const quickPickButtons = [
     { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
@@ -19,7 +19,7 @@ export async function selectRunnable(
     debuggeeOnly = false,
     showButtons: boolean = true,
 ): Promise<RunnableQuickPick | undefined> {
-    const editor = ctx.activeRustEditor;
+    const editor = ctx.activeRustEditor ?? ctx.activeCargoTomlEditor;
     if (!editor) return;
 
     // show a placeholder while we get the runnables from the server
@@ -175,10 +175,17 @@ async function getRunnables(
         uri: editor.document.uri.toString(),
     };
 
-    const runnables = await client.sendRequest(ra.runnables, {
-        textDocument,
-        position: client.code2ProtocolConverter.asPosition(editor.selection.active),
-    });
+    const runnables = await client
+        .sendRequest(ra.runnables, {
+            textDocument,
+            position: client.code2ProtocolConverter.asPosition(editor.selection.active),
+        })
+        .catch((err) => {
+            // If this command is run for a virtual manifest at the workspace root, then this request
+            // will fail as we do not watch this file.
+            log.error(`${err}`);
+            return [];
+        });
     const items: RunnableQuickPick[] = [];
     if (prevRunnable) {
         items.push(prevRunnable);
diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts
index 2f7702baebb..93c7bf8d73e 100644
--- a/src/tools/rust-analyzer/editors/code/src/util.ts
+++ b/src/tools/rust-analyzer/editors/code/src/util.ts
@@ -90,6 +90,10 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
     return isRustDocument(editor.document);
 }
 
+export function isCargoTomlEditor(editor: vscode.TextEditor): editor is RustEditor {
+    return isCargoTomlDocument(editor.document);
+}
+
 export function isDocumentInWorkspace(document: RustDocument): boolean {
     const workspaceFolders = vscode.workspace.workspaceFolders;
     if (!workspaceFolders) {
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index e24e08d0687..0db4be8ff63 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-daf59857d6d2b87af4b846316bf1561a6083ed51
+2c6a12ec44d0426c8939123c2f2cf27d2217de13
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 16b7e7aa709..eff2d2e3ff4 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -137,6 +137,10 @@ pub(crate) fn format_expr(
         ast::ExprKind::Tup(ref items) => {
             rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
         }
+        ast::ExprKind::Use(_, _) => {
+            // FIXME: properly implement this
+            Ok(context.snippet(expr.span()).to_owned())
+        }
         ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
         ast::ExprKind::If(..)
         | ast::ExprKind::ForLoop { .. }
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index ba4a4c045f1..fe716c18638 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -513,6 +513,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Become(..)
         | ast::ExprKind::Yeet(..)
         | ast::ExprKind::Tup(..)
+        | ast::ExprKind::Use(..)
         | ast::ExprKind::Type(..)
         | ast::ExprKind::Yield(None)
         | ast::ExprKind::Underscore => false,
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 9a4d0891b4a..dfdbc0878f2 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -17,6 +17,7 @@ termcolor = "1.1.3"
 rustc-hash = "2.0.0"
 fluent-syntax = "0.11.1"
 similar = "2.5.0"
+toml = "0.7.8"
 
 [features]
 build-metrics = ["dep:serde"]
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 51e58b4e4fc..569d3c67b04 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -1,11 +1,12 @@
 //! Checks the licenses of third-party dependencies.
 
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
 use std::fs::{File, read_dir};
 use std::io::Write;
 use std::path::Path;
 
 use build_helper::ci::CiEnv;
+use cargo_metadata::semver::Version;
 use cargo_metadata::{Metadata, Package, PackageId};
 
 #[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"]
@@ -123,7 +124,6 @@ const EXCEPTIONS_CARGO: ExceptionList = &[
     ("arrayref", "BSD-2-Clause"),
     ("bitmaps", "MPL-2.0+"),
     ("blake3", "CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception"),
-    ("bytesize", "Apache-2.0"),
     ("ciborium", "Apache-2.0"),
     ("ciborium-io", "Apache-2.0"),
     ("ciborium-ll", "Apache-2.0"),
@@ -446,6 +446,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "windows_x86_64_gnu",
     "windows_x86_64_gnullvm",
     "windows_x86_64_msvc",
+    "wit-bindgen-rt@0.33.0", // via wasi
     "writeable",
     "yoke",
     "yoke-derive",
@@ -803,7 +804,17 @@ fn check_permitted_dependencies(
 
     // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
     for permitted in permitted_dependencies {
-        if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) {
+        fn compare(pkg: &Package, permitted: &str) -> bool {
+            if let Some((name, version)) = permitted.split_once("@") {
+                let Ok(version) = Version::parse(version) else {
+                    return false;
+                };
+                pkg.name == name && pkg.version == version
+            } else {
+                pkg.name == permitted
+            }
+        }
+        if !deps.iter().any(|dep_id| compare(pkg_from_id(metadata, dep_id), permitted)) {
             tidy_error!(
                 bad,
                 "could not find allowed package `{permitted}`\n\
@@ -814,14 +825,30 @@ fn check_permitted_dependencies(
     }
 
     // Get in a convenient form.
-    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
+    let permitted_dependencies: HashMap<_, _> = permitted_dependencies
+        .iter()
+        .map(|s| {
+            if let Some((name, version)) = s.split_once('@') {
+                (name, Version::parse(version).ok())
+            } else {
+                (*s, None)
+            }
+        })
+        .collect();
 
     for dep in deps {
         let dep = pkg_from_id(metadata, dep);
         // If this path is in-tree, we don't require it to be explicitly permitted.
-        if dep.source.is_some() && !permitted_dependencies.contains(dep.name.as_str()) {
-            tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
-            has_permitted_dep_error = true;
+        if dep.source.is_some() {
+            let is_eq = if let Some(version) = permitted_dependencies.get(dep.name.as_str()) {
+                if let Some(version) = version { version == &dep.version } else { true }
+            } else {
+                false
+            };
+            if !is_eq {
+                tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
+                has_permitted_dep_error = true;
+            }
         }
     }
 
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 9f6d563166e..66856f5247b 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -87,6 +87,7 @@ pub mod target_policy;
 pub mod target_specific_tests;
 pub mod tests_placement;
 pub mod tests_revision_unpaired_stdout_stderr;
+pub mod triagebot;
 pub mod ui_tests;
 pub mod unit_tests;
 pub mod unknown_revision;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 1d8514ef4c9..bc3519142dd 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -144,6 +144,8 @@ fn main() {
 
         check!(x_version, &root_path, &cargo);
 
+        check!(triagebot, &root_path);
+
         let collected = {
             drain_handles(&mut handles);
 
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 205d6720718..2237eac200d 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -475,7 +475,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                 && !trimmed.starts_with("//")
                 && !file.ancestors().any(|a| {
                     (a.ends_with("tests") && a.join("COMPILER_TESTS.md").exists())
-                        || a.ends_with("library/alloc/tests")
+                        || a.ends_with("library/alloctests")
                 })
                 && filename != "tests.rs"
             {
diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs
new file mode 100644
index 00000000000..7131c16ec30
--- /dev/null
+++ b/src/tools/tidy/src/triagebot.rs
@@ -0,0 +1,93 @@
+//! Tidy check to ensure paths mentioned in triagebot.toml exist in the project.
+
+use std::path::Path;
+
+use toml::Value;
+
+pub fn check(path: &Path, bad: &mut bool) {
+    let triagebot_path = path.join("triagebot.toml");
+    if !triagebot_path.exists() {
+        tidy_error!(bad, "triagebot.toml file not found");
+        return;
+    }
+
+    let contents = std::fs::read_to_string(&triagebot_path).unwrap();
+    let config: Value = toml::from_str(&contents).unwrap();
+
+    // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"]
+    if let Some(Value::Table(mentions)) = config.get("mentions") {
+        for path_str in mentions.keys() {
+            // Remove quotes from the path
+            let clean_path = path_str.trim_matches('"');
+            let full_path = path.join(clean_path);
+
+            if !full_path.exists() {
+                tidy_error!(
+                    bad,
+                    "triagebot.toml [mentions.*] contains path '{}' which doesn't exist",
+                    clean_path
+                );
+            }
+        }
+    } else {
+        tidy_error!(
+            bad,
+            "triagebot.toml missing [mentions.*] section, this wrong for rust-lang/rust repo."
+        );
+    }
+
+    // Check [assign.owners] sections, i.e.
+    // [assign.owners]
+    // "/.github/workflows" = ["infra-ci"]
+    if let Some(Value::Table(assign)) = config.get("assign") {
+        if let Some(Value::Table(owners)) = assign.get("owners") {
+            for path_str in owners.keys() {
+                // Remove quotes and leading slash from the path
+                let clean_path = path_str.trim_matches('"').trim_start_matches('/');
+                let full_path = path.join(clean_path);
+
+                if !full_path.exists() {
+                    tidy_error!(
+                        bad,
+                        "triagebot.toml [assign.owners] contains path '{}' which doesn't exist",
+                        clean_path
+                    );
+                }
+            }
+        } else {
+            tidy_error!(
+                bad,
+                "triagebot.toml missing [assign.owners] section, this wrong for rust-lang/rust repo."
+            );
+        }
+    }
+
+    // Verify that trigger_files in [autolabel."*"] exist in the project, i.e.
+    // [autolabel."A-rustdoc-search"]
+    // trigger_files = [
+    //    "src/librustdoc/html/static/js/search.js",
+    //    "tests/rustdoc-js",
+    //    "tests/rustdoc-js-std",
+    // ]
+    if let Some(Value::Table(autolabels)) = config.get("autolabel") {
+        for (label, content) in autolabels {
+            if let Some(trigger_files) = content.get("trigger_files").and_then(|v| v.as_array()) {
+                for file in trigger_files {
+                    if let Some(file_str) = file.as_str() {
+                        let full_path = path.join(file_str);
+
+                        // Handle both file and directory paths
+                        if !full_path.exists() {
+                            tidy_error!(
+                                bad,
+                                "triagebot.toml [autolabel.{}] contains trigger_files path '{}' which doesn't exist",
+                                label,
+                                file_str
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs
index e9ba0f9ba89..a937256a60f 100644
--- a/tests/assembly/stack-protector/stack-protector-target-support.rs
+++ b/tests/assembly/stack-protector/stack-protector-target-support.rs
@@ -3,7 +3,7 @@
 //
 //@ add-core-stubs
 //@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23
-//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33     r35 r36 r37 r38 r39 r40 r41 r42 r43 r44
+//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33         r36 r37 r38 r39 r40 r41 r42 r43 r44
 //@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65
 //@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85
 //@ assembly-output: emit-asm
@@ -73,9 +73,6 @@
 //@ [r32] needs-llvm-components: arm
 //@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf
 //@ [r33] needs-llvm-components: arm
-
-//@ [r35] compile-flags: --target i586-pc-windows-msvc
-//@ [r35] needs-llvm-components: x86
 //@ [r36] compile-flags: --target i586-unknown-linux-gnu
 //@ [r36] needs-llvm-components: x86
 //@ [r37] compile-flags: --target i586-unknown-linux-musl
@@ -195,7 +192,6 @@ pub fn foo() {
     // r3: calll @__security_check_cookie
     // r7: callq __security_check_cookie
     // r13: bl __security_check_cookie
-    // r35: calll @__security_check_cookie
 
     // cuda doesn't support stack-smash protection
     // r49-NOT: __security_check_cookie
diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs
index f895b79ba50..de29b9af502 100644
--- a/tests/assembly/targets/targets-pe.rs
+++ b/tests/assembly/targets/targets-pe.rs
@@ -25,9 +25,6 @@
 //@ revisions: bpfel_unknown_none
 //@ [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none
 //@ [bpfel_unknown_none] needs-llvm-components: bpf
-//@ revisions: i586_pc_windows_msvc
-//@ [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc
-//@ [i586_pc_windows_msvc] needs-llvm-components: x86
 //@ revisions: i686_pc_windows_gnu
 //@ [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu
 //@ [i686_pc_windows_gnu] needs-llvm-components: x86
diff --git a/tests/codegen/asm/critical.rs b/tests/codegen/asm/critical.rs
new file mode 100644
index 00000000000..8c039900cab
--- /dev/null
+++ b/tests/codegen/asm/critical.rs
@@ -0,0 +1,37 @@
+//@ only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+#![feature(asm_goto)]
+#![feature(asm_goto_with_outputs)]
+#![crate_type = "lib"]
+use std::arch::asm;
+
+// Regression test for #137867. Check that critical edges have been split before code generation,
+// and so all stores to the asm output occur on disjoint paths without any of them jumping to
+// another callbr label.
+//
+// CHECK-LABEL: @f(
+// CHECK:        [[OUT:%.*]] = callbr i32 asm
+// CHECK-NEXT:   to label %[[BB0:.*]] [label %[[BB1:.*]], label %[[BB2:.*]]],
+// CHECK:       [[BB1]]:
+// CHECK-NEXT:    store i32 [[OUT]], ptr %a
+// CHECK-NEXT:    br label %[[BBR:.*]]
+// CHECK:       [[BB2]]:
+// CHECK-NEXT:    store i32 [[OUT]], ptr %a
+// CHECK-NEXT:    br label %[[BBR]]
+// CHECK:       [[BB0]]:
+// CHECK-NEXT:    store i32 [[OUT]], ptr %a
+// CHECK-NEXT:    br label %[[BBR]]
+// CHECK:       [[BBR]]:
+// CHECK-NEXT:    [[RET:%.*]] = load i32, ptr %a
+// CHECK-NEXT:    ret i32 [[RET]]
+#[unsafe(no_mangle)]
+pub unsafe fn f(mut a: u32) -> u32 {
+    asm!(
+        "jmp {}
+         jmp {}",
+        label {},
+        label {},
+        inout("eax") a,
+    );
+    a
+}
diff --git a/tests/codegen/enum/enum-two-variants-match.rs b/tests/codegen/enum/enum-two-variants-match.rs
new file mode 100644
index 00000000000..e5978bfc761
--- /dev/null
+++ b/tests/codegen/enum/enum-two-variants-match.rs
@@ -0,0 +1,51 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ min-llvm-version: 19 (for trunc nuw)
+//@ only-x86_64 (because these discriminants are isize)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @option_match
+#[no_mangle]
+pub fn option_match(x: Option<i32>) -> u16 {
+    // CHECK: %x = alloca [8 x i8]
+    // CHECK: store i32 %0, ptr %x
+    // CHECK: %[[TAG:.+]] = load i32, ptr %x
+    // CHECK-SAME: !range ![[ZERO_ONE_32:[0-9]+]]
+    // CHECK: %[[DISCR:.+]] = zext i32 %[[TAG]] to i64
+    // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1
+    // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]]
+
+    // CHECK: [[TRUE]]:
+    // CHECK: store i16 13
+
+    // CHECK: [[FALSE]]:
+    // CHECK: store i16 42
+    match x {
+        Some(_) => 13,
+        None => 42,
+    }
+}
+
+// CHECK-LABEL: @result_match
+#[no_mangle]
+pub fn result_match(x: Result<u64, i64>) -> u16 {
+    // CHECK: %x = alloca [16 x i8]
+    // CHECK: store i64 %0, ptr %x
+    // CHECK: %[[DISCR:.+]] = load i64, ptr %x
+    // CHECK-SAME: !range ![[ZERO_ONE_64:[0-9]+]]
+    // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1
+    // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]]
+
+    // CHECK: [[TRUE]]:
+    // CHECK: store i16 13
+
+    // CHECK: [[FALSE]]:
+    // CHECK: store i16 42
+    match x {
+        Err(_) => 13,
+        Ok(_) => 42,
+    }
+}
+
+// CHECK: ![[ZERO_ONE_32]] = !{i32 0, i32 2}
+// CHECK: ![[ZERO_ONE_64]] = !{i64 0, i64 2}
diff --git a/tests/codegen/intrinsics/cold_path2.rs b/tests/codegen/intrinsics/cold_path2.rs
index 1e7e0478f4f..54ee473e620 100644
--- a/tests/codegen/intrinsics/cold_path2.rs
+++ b/tests/codegen/intrinsics/cold_path2.rs
@@ -26,7 +26,8 @@ pub fn test(x: Option<bool>) {
     }
 
     // CHECK-LABEL: @test(
-    // CHECK: br i1 %1, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]]
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %0, 2
+    // CHECK: br i1 %[[IS_NONE]], label %bb2, label %bb1, !prof ![[NUM:[0-9]+]]
     // CHECK: bb1:
     // CHECK: path_a
     // CHECK: bb2:
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs
index ff297b27065..4849b88c09c 100644
--- a/tests/codegen/intrinsics/transmute.rs
+++ b/tests/codegen/intrinsics/transmute.rs
@@ -10,6 +10,7 @@
 use std::intrinsics::mir::*;
 use std::intrinsics::{transmute, transmute_unchecked};
 use std::mem::MaybeUninit;
+use std::num::NonZero;
 
 // FIXME(LLVM18REMOVED): `trunc nuw` doesn't exist in LLVM 18, so once we no
 // longer support it the optional flag checks can be changed to required.
@@ -470,3 +471,27 @@ pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 {
     // CHECK: ret i64 %[[VAL]]
     transmute(x)
 }
+
+#[repr(transparent)]
+struct Level1(std::num::NonZero<u32>);
+#[repr(transparent)]
+struct Level2(Level1);
+#[repr(transparent)]
+struct Level3(Level2);
+
+// CHECK-LABEL: @repeatedly_transparent_transmute
+// CHECK-SAME: (i32{{.+}}%[[ARG:[^)]+]])
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn repeatedly_transparent_transmute(x: NonZero<u32>) -> Level3 {
+    // CHECK: start
+    // CHECK-NEXT: ret i32 %[[ARG]]
+    mir! {
+        {
+            let A = CastTransmute::<NonZero<u32>, Level1>(x);
+            let B = CastTransmute::<Level1, Level2>(A);
+            RET = CastTransmute::<Level2, Level3>(B);
+            Return()
+        }
+    }
+}
diff --git a/tests/codegen/issues/auxiliary/static_dllimport_aux.rs b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs
deleted file mode 100644
index afb0dc42f44..00000000000
--- a/tests/codegen/issues/auxiliary/static_dllimport_aux.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use std::sync::atomic::{AtomicPtr, Ordering};
-
-#[inline(always)]
-pub fn memrchr() {
-    fn detect() {}
-
-    static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ());
-
-    unsafe {
-        let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst);
-        std::mem::transmute::<*mut (), fn()>(fun)()
-    }
-}
diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs
index 048b69d207b..7fb850ca253 100644
--- a/tests/codegen/issues/issue-101082.rs
+++ b/tests/codegen/issues/issue-101082.rs
@@ -1,5 +1,6 @@
 //@ compile-flags: -Copt-level=3
 //@ revisions: host x86-64-v3
+//@ min-llvm-version: 20
 
 // This particular CPU regressed in #131563
 //@[x86-64-v3] only-x86_64
diff --git a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs
index fdb8f06df80..fbea4ee8979 100644
--- a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs
+++ b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs
@@ -3,6 +3,11 @@
 
 #![crate_type = "lib"]
 
+// The bug here was that it was loading and storing the whole value.
+// It's ok for it to load the discriminant,
+// to preserve the UB from `unreachable_unchecked`,
+// but it better only store the constant discriminant of `B`.
+
 pub enum State {
     A([u8; 753]),
     B([u8; 753]),
@@ -11,9 +16,27 @@ pub enum State {
 // CHECK-LABEL: @update
 #[no_mangle]
 pub unsafe fn update(s: *mut State) {
-    // CHECK-NEXT: start:
-    // CHECK-NEXT: store i8
-    // CHECK-NEXT: ret
+    // CHECK-NOT: alloca
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: 75{{3|4}}
+
+    // CHECK: %[[TAG:.+]] = load i8, ptr %s, align 1
+    // CHECK-NEXT: trunc nuw i8 %[[TAG]] to i1
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: 75{{3|4}}
+
+    // CHECK: store i8 1, ptr %s, align 1
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: 75{{3|4}}
     let State::A(v) = s.read() else { std::hint::unreachable_unchecked() };
     s.write(State::B(v));
 }
diff --git a/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs
deleted file mode 100644
index 4023412f23c..00000000000
--- a/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ compile-flags: -Copt-level=3 -C lto=thin -C prefer-dynamic=no
-//@ only-windows
-//@ aux-build:static_dllimport_aux.rs
-
-// Test that on Windows, when performing ThinLTO, we do not mark cross-crate static items with
-// dllimport because lld does not fix the symbol names for us.
-
-extern crate static_dllimport_aux;
-
-// CHECK-LABEL: @{{.+}}CROSS_CRATE_STATIC_ITEM{{.+}} =
-// CHECK-SAME: external local_unnamed_addr global %"{{.+}}AtomicPtr
-
-pub fn main() {
-    static_dllimport_aux::memrchr();
-}
diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs
index 73bdbc0e1a8..5d54444f994 100644
--- a/tests/codegen/target-feature-inline-closure.rs
+++ b/tests/codegen/target-feature-inline-closure.rs
@@ -12,7 +12,7 @@ use std::arch::x86_64::*;
 #[cfg(target_arch = "x86_64")]
 #[target_feature(enable = "avx")]
 fn with_avx(x: __m256) -> __m256 {
-    // CHECK: fadd
+    // CHECK: fadd <8 x float>
     let add = {
         #[inline(always)]
         |x, y| unsafe { _mm256_add_ps(x, y) }
@@ -24,14 +24,10 @@ fn with_avx(x: __m256) -> __m256 {
 #[no_mangle]
 #[cfg(target_arch = "x86_64")]
 unsafe fn without_avx(x: __m256) -> __m256 {
-    // CHECK-NOT: fadd
+    // CHECK-NOT: fadd <8 x float>
     let add = {
         #[inline(always)]
         |x, y| unsafe { _mm256_add_ps(x, y) }
     };
     add(x, x)
 }
-
-// Don't allow the above CHECK-NOT to accidentally match a commit hash in the
-// compiler version.
-// CHECK-LABEL: rustc version
diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs
index 751d7ca9311..ca15e510173 100644
--- a/tests/codegen/try_question_mark_nop.rs
+++ b/tests/codegen/try_question_mark_nop.rs
@@ -16,8 +16,8 @@ use std::ptr::NonNull;
 #[no_mangle]
 pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
     // CHECK: start:
-    // TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1
-    // TWENTY-NEXT: %.2 = select i1 %trunc, i32 %1, i32 undef
+    // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
+    // TWENTY-NEXT: %.2 = select i1 %[[IS_SOME]], i32 %1, i32 undef
     // CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
     // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
     // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %.2, 1
@@ -32,8 +32,8 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
 #[no_mangle]
 pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> {
     // CHECK: start:
-    // TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1
-    // TWENTY-NEXT: %.1 = select i1 %trunc, i32 %1, i32 undef
+    // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
+    // TWENTY-NEXT: %.1 = select i1 %[[IS_SOME]], i32 %1, i32 undef
     // CHECK-NEXT: insertvalue { i32, i32 }
     // CHECK-NEXT: insertvalue { i32, i32 }
     // CHECK-NEXT: ret { i32, i32 }
diff --git a/tests/crashes/127916.rs b/tests/crashes/127916.rs
deleted file mode 100644
index 295c88df857..00000000000
--- a/tests/crashes/127916.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: #127916
-
-trait Trait {
-    fn foo(&self) -> u32 { 0 }
-}
-
-struct F;
-struct S;
-
-mod to_reuse {
-    pub fn foo(&self) -> u32 {}
-}
-
-impl Trait  S {
-    reuse to_reuse::foo { self }
-}
diff --git a/tests/crashes/128119.rs b/tests/crashes/128119.rs
deleted file mode 100644
index 7677b15a2f3..00000000000
--- a/tests/crashes/128119.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #128119
-
-trait Trait {
-    reuse to_reuse::foo { self }
-}
-
-struct S;
-
-mod to_reuse {
-    pub fn foo(&self) -> u32 {}
-}
-
-impl Trait  S {
-    reuse to_reuse::foo { self }
-}
diff --git a/tests/crashes/128190.rs b/tests/crashes/128190.rs
deleted file mode 100644
index 0fa7027ae60..00000000000
--- a/tests/crashes/128190.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ known-bug: rust-lang/rust#128190
-
-fn a(&self) {
-    15
-}
-
-reuse a as b {  struct S; }
diff --git a/tests/crashes/133426.rs b/tests/crashes/133426.rs
deleted file mode 100644
index 307a94c0f6c..00000000000
--- a/tests/crashes/133426.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ known-bug: #133426
-
-fn a(
-    _: impl Iterator<
-        Item = [(); {
-                   match *todo!() { ! };
-               }],
-    >,
-) {
-}
-
-fn b(_: impl Iterator<Item = { match 0 { ! } }>) {}
diff --git a/tests/crashes/136138.rs b/tests/crashes/136138.rs
new file mode 100644
index 00000000000..c3893dc9c8e
--- /dev/null
+++ b/tests/crashes/136138.rs
@@ -0,0 +1,7 @@
+//@ known-bug: #136138
+#![feature(min_generic_const_args)]
+struct U;
+struct S<const N: U>()
+where
+    S<{ U }>:;
+fn main() {}
diff --git a/tests/crashes/136175-2.rs b/tests/crashes/136175-2.rs
new file mode 100644
index 00000000000..28f8ff7fd1c
--- /dev/null
+++ b/tests/crashes/136175-2.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #136175
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+
+struct A<T>(T)
+where
+    [(); std::mem::offset_of!((T,), 0)]:;
+
+fn main() {
+    let x: A<dyn Trait>;
+}
diff --git a/tests/crashes/136175.rs b/tests/crashes/136175.rs
new file mode 100644
index 00000000000..0b5f2fdaa92
--- /dev/null
+++ b/tests/crashes/136175.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #136175
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+
+struct A<T>(T)
+where
+    [(); size_of::<T>()]:;
+
+fn main() {
+    let x: A<dyn Trait>;
+}
diff --git a/tests/crashes/136188.rs b/tests/crashes/136188.rs
new file mode 100644
index 00000000000..a701fc4c0b7
--- /dev/null
+++ b/tests/crashes/136188.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #136188
+//@ compile-flags: --crate-type=lib -Znext-solver
+#![feature(type_alias_impl_trait)]
+
+type Opaque = Box<impl Sized>;
+
+fn define() -> Opaque { Box::new(()) }
+
+impl Copy for Opaque {}
diff --git a/tests/crashes/136286.rs b/tests/crashes/136286.rs
new file mode 100644
index 00000000000..f0ea14bd167
--- /dev/null
+++ b/tests/crashes/136286.rs
@@ -0,0 +1,7 @@
+//@ known-bug: #136286
+//@ compile-flags: --edition=2024
+
+#![feature(async_fn_in_dyn_trait)]
+trait A {
+    async fn b(self: A);
+}
diff --git a/tests/crashes/136379.rs b/tests/crashes/136379.rs
new file mode 100644
index 00000000000..077b373e3b5
--- /dev/null
+++ b/tests/crashes/136379.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #136379
+#![feature(min_generic_const_args)]
+pub struct S();
+
+impl S {
+    pub fn f() -> [u8; S] {
+        []
+    }
+}
+
+pub fn main() {}
diff --git a/tests/crashes/136381.rs b/tests/crashes/136381.rs
new file mode 100644
index 00000000000..13ccc14a2c5
--- /dev/null
+++ b/tests/crashes/136381.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #136381
+//@ compile-flags: -Zvalidate-mir -Zmir-enable-passes=+GVN
+#![feature(trait_upcasting)]
+
+trait A {}
+trait B: A {
+    fn c(&self);
+}
+impl B for i32 {
+    fn c(self) {
+        todo!();
+    }
+}
+
+fn main() {
+    let baz: &dyn B = &1;
+    let bar: &dyn A = baz;
+}
diff --git a/tests/crashes/136416.rs b/tests/crashes/136416.rs
new file mode 100644
index 00000000000..b233422af86
--- /dev/null
+++ b/tests/crashes/136416.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #136416
+#![feature(generic_const_exprs)]
+struct State<const S : usize = {}> where[(); S] :;
+
+struct Foo;
+struct State2<const S: usize = Foo> where [(); S]:;
diff --git a/tests/crashes/136442.rs b/tests/crashes/136442.rs
new file mode 100644
index 00000000000..0436debd565
--- /dev/null
+++ b/tests/crashes/136442.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #136442
+//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+Inline -Zmir-enable-passes=+JumpThreading --crate-type lib
+pub fn problem_thingy(items: &mut impl Iterator<Item = str>) {
+    let mut peeker = items.peekable();
+    match peeker.peek() {
+        Some(_) => (),
+        None => return (),
+    }
+}
diff --git a/tests/crashes/136661.rs b/tests/crashes/136661.rs
new file mode 100644
index 00000000000..76161a566f4
--- /dev/null
+++ b/tests/crashes/136661.rs
@@ -0,0 +1,25 @@
+//@ known-bug: #136661
+
+#![allow(unused)]
+
+trait Supertrait<T> {}
+
+trait Other {
+    fn method(&self) {}
+}
+
+impl WithAssoc for &'static () {
+    type As = ();
+}
+
+trait WithAssoc {
+    type As;
+}
+
+trait Trait<P: WithAssoc>: Supertrait<P::As> {
+    fn method(&self) {}
+}
+
+fn hrtb<T: for<'a> Trait<&'a ()>>() {}
+
+pub fn main() {}
diff --git a/tests/crashes/136666.rs b/tests/crashes/136666.rs
new file mode 100644
index 00000000000..5cfed65fdf9
--- /dev/null
+++ b/tests/crashes/136666.rs
@@ -0,0 +1,36 @@
+//@ known-bug: #136666
+// Needed so that rust can infer that the A in what() is &()
+trait IsRef<T> {}
+struct Dummy;
+impl<'a> IsRef<&'a ()> for Dummy {}
+
+trait WithLifetime {
+    type Output<'a>;
+}
+impl<'t> WithLifetime for &'t () {
+    type Output<'a> = &'a ();
+}
+
+// Needed to prevent the two Foo impls from overlapping
+struct Wrap<A>(A);
+
+trait Unimplemented {}
+
+trait Foo {}
+impl<T> Foo for T where T: Unimplemented {}
+impl<A> Foo for Wrap<A>
+where
+    Dummy: IsRef<A>,
+    for<'a> A: WithLifetime<Output<'a> = A>,
+{
+}
+
+fn what<A>()
+where
+    Wrap<A>: Foo,
+{
+}
+
+fn main() {
+    what();
+}
diff --git a/tests/crashes/136678.rs b/tests/crashes/136678.rs
new file mode 100644
index 00000000000..e7d7de23bfe
--- /dev/null
+++ b/tests/crashes/136678.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #136678
+#![feature(inherent_associated_types)]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct B<const A: usize>;
+
+struct Test<const A: usize>;
+
+impl<const A: usize> Test<A> {
+    type B = B<{ A }>;
+
+    fn test(a: Self::B) -> Self::B {
+        a
+    }
+}
+
+pub fn main() {}
diff --git a/tests/crashes/136766.rs b/tests/crashes/136766.rs
new file mode 100644
index 00000000000..01fa07a05ae
--- /dev/null
+++ b/tests/crashes/136766.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #136766
+#![feature(generic_const_exprs)]
+trait A<const B: bool>{}
+impl A<true> for () {}
+fn c<const D: usize>(E: [u8; D * D]) where() : A<D>{}
+fn main() { c }
diff --git a/tests/crashes/136859.rs b/tests/crashes/136859.rs
new file mode 100644
index 00000000000..2c926eea5e2
--- /dev/null
+++ b/tests/crashes/136859.rs
@@ -0,0 +1,27 @@
+//@ known-bug: #136859
+#![feature(generic_const_exprs)]
+
+trait If<const COND: bool> {}
+impl If<true> for () {}
+
+trait IsZero<const N: u8> {
+    type Answer;
+}
+
+struct True;
+struct False;
+
+impl<const N: u8> IsZero<N> for ()
+where (): If<{N == 0}> {
+    type Msg = True;
+}
+
+trait Foobar<const N: u8> {}
+
+impl<const N: u8> Foobar<N> for ()
+where (): IsZero<N, Answer = True> {}
+
+impl<const N: u8> Foobar<{{ N }}> for ()
+where (): IsZero<N, Answer = False> {}
+
+fn main() {}
diff --git a/tests/crashes/136894.rs b/tests/crashes/136894.rs
new file mode 100644
index 00000000000..26bbb78717e
--- /dev/null
+++ b/tests/crashes/136894.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #136894
+#![feature(generic_const_exprs)]
+#![crate_type = "lib"]
+#![allow(incomplete_features, dead_code)]
+
+struct X<T>([(); f::<T>()]) where [(); f::<T>()]:;
+
+const fn f<T>() -> usize { panic!() }
diff --git a/tests/crashes/137049.rs b/tests/crashes/137049.rs
new file mode 100644
index 00000000000..a7132e4fa17
--- /dev/null
+++ b/tests/crashes/137049.rs
@@ -0,0 +1,29 @@
+//@ known-bug: #137049
+//@ compile-flags: --crate-type=lib
+#![feature(type_alias_impl_trait)]
+
+use std::marker::PhantomData;
+
+trait Project1 {
+    type Assoc1;
+}
+
+impl<T> Project1 for T {
+    type Assoc1 = ();
+}
+
+trait Project2 {
+    type Assoc2;
+}
+
+impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> {
+    type Assoc2 = ();
+}
+
+type Alias<T> = impl Project2;
+
+fn constrain<T>() -> Alias<T> {
+    PhantomData::<T>
+}
+
+struct AdtConstructor<T: Project1>(<Alias<T> as Project2>::Assoc2);
diff --git a/tests/crashes/137084.rs b/tests/crashes/137084.rs
new file mode 100644
index 00000000000..0f248c21206
--- /dev/null
+++ b/tests/crashes/137084.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #137084
+#![feature(min_generic_const_args)]
+fn a<const b: i32>() {}
+fn d(e: &String) {
+    a::<d>
+}
diff --git a/tests/crashes/137187.rs b/tests/crashes/137187.rs
new file mode 100644
index 00000000000..05cfb2b10e1
--- /dev/null
+++ b/tests/crashes/137187.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #137187
+use std::ops::Add;
+trait A where
+    *const Self: Add,
+{
+    const fn b(c: *const Self) -> <*const Self as Add>::Output {
+        c + c
+    }
+}
diff --git a/tests/crashes/137188.rs b/tests/crashes/137188.rs
new file mode 100644
index 00000000000..fdd098d300f
--- /dev/null
+++ b/tests/crashes/137188.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #137188
+#![feature(min_generic_const_args)]
+trait Trait {}
+impl Trait for [(); N] {}
+fn N<T>() {}
+pub fn main() {}
diff --git a/tests/crashes/137190-1.rs b/tests/crashes/137190-1.rs
new file mode 100644
index 00000000000..bdfe883b712
--- /dev/null
+++ b/tests/crashes/137190-1.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #137190
+//@ compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
+trait A {
+    fn b(&self);
+}
+trait C: A {}
+impl C for () {}
+fn main() {
+    (&() as &dyn C as &dyn A).b();
+}
diff --git a/tests/crashes/137190-2.rs b/tests/crashes/137190-2.rs
new file mode 100644
index 00000000000..0c68b5aa4a5
--- /dev/null
+++ b/tests/crashes/137190-2.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #137190
+trait Supertrait<T> {
+    fn method(&self) {}
+}
+
+trait Trait<P>: Supertrait<()> {}
+
+impl<P> Trait<P> for () {}
+
+const fn upcast<P>(x: &dyn Trait<P>) -> &dyn Supertrait<()> {
+    x
+}
+
+const fn foo() -> &'static dyn Supertrait<()> {
+    upcast::<()>(&())
+}
+
+const _: &'static dyn Supertrait<()> = foo();
diff --git a/tests/crashes/137190-3.rs b/tests/crashes/137190-3.rs
new file mode 100644
index 00000000000..88ae88e11bc
--- /dev/null
+++ b/tests/crashes/137190-3.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #137190
+trait Supertrait {
+    fn method(&self) {}
+}
+
+trait Trait: Supertrait {}
+
+impl Trait for () {}
+
+const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait;
diff --git a/tests/crashes/137260.rs b/tests/crashes/137260.rs
new file mode 100644
index 00000000000..f1fa8a660dc
--- /dev/null
+++ b/tests/crashes/137260.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #137260
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Iter<const N: usize = { 1 + true }> {}
+
+fn needs_iter<const N: usize, T: Iter<N>>() {}
+
+fn test() {
+    needs_iter::<1, dyn Iter<()>>();
+}
diff --git a/tests/crashes/137287.rs b/tests/crashes/137287.rs
new file mode 100644
index 00000000000..59fdf568d36
--- /dev/null
+++ b/tests/crashes/137287.rs
@@ -0,0 +1,29 @@
+//@ known-bug: #137287
+
+mod defining_scope {
+    use super::*;
+    pub type Alias<T> = impl Sized;
+
+    pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
+        x
+    }
+}
+
+struct Container<T: Trait<U>, U> {
+    x: <T as Trait<U>>::Assoc,
+}
+
+trait Trait<T> {
+    type Assoc;
+}
+
+impl<T> Trait<T> for T {
+    type Assoc = Box<u32>;
+}
+impl<T> Trait<T> for defining_scope::Alias<T> {
+    type Assoc = usize;
+}
+
+fn main() {
+    let x: Box<u32> = defining_scope::cast::<()>(Container { x: 0 }).x;
+}
diff --git a/tests/crashes/137467-1.rs b/tests/crashes/137467-1.rs
new file mode 100644
index 00000000000..1d62cba59a7
--- /dev/null
+++ b/tests/crashes/137467-1.rs
@@ -0,0 +1,17 @@
+//@ known-bug: #137467
+//@ compile-flags: --edition=2021
+enum Camera {
+    Normal { base_transform: i32 },
+    Volume { transform: i32 },
+}
+
+fn draw_ui(camera: &mut Camera) {
+    || {
+        let (Camera::Normal {
+            base_transform: _transform,
+        }
+        | Camera::Volume {
+            transform: _transform,
+        }) = camera;
+    };
+}
diff --git a/tests/crashes/137467-2.rs b/tests/crashes/137467-2.rs
new file mode 100644
index 00000000000..151d6a0767f
--- /dev/null
+++ b/tests/crashes/137467-2.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #137467
+//@ compile-flags: --edition=2021
+
+enum Camera {
+    Normal { base_transform: i32 },
+    Volume { transform: i32 },
+}
+
+fn draw_ui(camera: &mut Camera) {
+    || {
+        let (Camera::Normal {
+            base_transform: _,
+        }
+        | Camera::Volume {
+            transform: _,
+        }) = camera;
+    };
+}
diff --git a/tests/crashes/137467-3.rs b/tests/crashes/137467-3.rs
new file mode 100644
index 00000000000..2140fe044a7
--- /dev/null
+++ b/tests/crashes/137467-3.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #137467
+//@ compile-flags: --edition=2021
+
+fn meow(x: (u32, u32, u32)) {
+    let f = || {
+        let ((0, a, _) | (_, _, a)) = x;
+    };
+}
diff --git a/tests/crashes/137468.rs b/tests/crashes/137468.rs
new file mode 100644
index 00000000000..cceb0502bd2
--- /dev/null
+++ b/tests/crashes/137468.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #137468
+//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+GVN -Zvalidate-mir
+trait Supertrait<T> {}
+
+trait Identity {
+    type Selff;
+}
+
+trait Trait<P>: Supertrait<()> + Supertrait<<P as Identity>::Selff> {}
+
+impl<P> Trait<P> for () {}
+
+fn main() {
+    let x: &dyn Trait<()> = &();
+    let x: &dyn Supertrait<()> = x;
+}
diff --git a/tests/crashes/137514.rs b/tests/crashes/137514.rs
new file mode 100644
index 00000000000..7ae5f29e36e
--- /dev/null
+++ b/tests/crashes/137514.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #137514
+//@ needs-rustc-debug-assertions
+#![feature(generic_const_exprs)]
+
+trait Bar<const N: usize> {}
+
+trait BB = Bar<{ 1i32 + 1 }>;
+
+fn foo(x: &dyn BB) {}
diff --git a/tests/crashes/137580.rs b/tests/crashes/137580.rs
new file mode 100644
index 00000000000..246c80ef556
--- /dev/null
+++ b/tests/crashes/137580.rs
@@ -0,0 +1,4 @@
+//@ known-bug: #137580
+fn main() {
+    println!("%65536$", 1);
+}
diff --git a/tests/crashes/137582.rs b/tests/crashes/137582.rs
new file mode 100644
index 00000000000..e21b6c9578b
--- /dev/null
+++ b/tests/crashes/137582.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #137582
+#![feature(adt_const_params)]
+
+mod lib {
+    pub type Matrix = [&'static u32];
+
+    const EMPTY_MATRIX: Matrix = [[0; 4]; 4];
+
+    pub struct Walk<const CURRENT: usize, const REMAINING: Matrix> {
+        _p: (),
+    }
+
+    impl<const CURRENT: usize> Walk<CURRENT, EMPTY_MATRIX> {}
+}
+
+fn main() {}
diff --git a/tests/crashes/137706.rs b/tests/crashes/137706.rs
new file mode 100644
index 00000000000..0b46f9c237a
--- /dev/null
+++ b/tests/crashes/137706.rs
@@ -0,0 +1,7 @@
+//@ known-bug: #137706
+//@ needs-rustc-debug-assertions
+trait A {
+    fn b() -> impl IntoIterator<Item = ()>;
+}
+
+impl A<()> for dyn A {}
diff --git a/tests/crashes/137751.rs b/tests/crashes/137751.rs
new file mode 100644
index 00000000000..85ae3acd53d
--- /dev/null
+++ b/tests/crashes/137751.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #137751
+//@ compile-flags: --edition=2021 -Znext-solver=globally
+async fn test() {
+    Box::pin(test()).await;
+}
+fn main() {}
diff --git a/tests/crashes/137813.rs b/tests/crashes/137813.rs
new file mode 100644
index 00000000000..5d205ee5331
--- /dev/null
+++ b/tests/crashes/137813.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #137813
+trait AssocConst {
+    const A: u8;
+}
+
+impl<T> AssocConst for (T,) {
+    const A: u8 = 0;
+}
+
+trait Trait {}
+
+impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
+
+fn foo()
+where
+    (): Trait,
+{
+}
diff --git a/tests/crashes/137865.rs b/tests/crashes/137865.rs
new file mode 100644
index 00000000000..7ecd8c734d3
--- /dev/null
+++ b/tests/crashes/137865.rs
@@ -0,0 +1,5 @@
+//@ known-bug: #137865
+trait Foo {
+    type Assoc<const N: Self>;
+    fn foo() -> Self::Assoc<3>;
+}
diff --git a/tests/crashes/137874.rs b/tests/crashes/137874.rs
new file mode 100644
index 00000000000..44718809024
--- /dev/null
+++ b/tests/crashes/137874.rs
@@ -0,0 +1,4 @@
+//@ known-bug: #137874
+fn a() {
+    match b { deref !(0c) };
+}
diff --git a/tests/crashes/137888.rs b/tests/crashes/137888.rs
new file mode 100644
index 00000000000..6c13ae5fa91
--- /dev/null
+++ b/tests/crashes/137888.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #137888
+#![feature(generic_const_exprs)]
+macro_rules! empty {
+    () => ();
+}
+fn bar<const N: i32>() -> [(); {
+       empty! {};
+       N
+   }] {
+}
+fn main() {}
diff --git a/tests/crashes/137895.rs b/tests/crashes/137895.rs
new file mode 100644
index 00000000000..bb624d2e9fa
--- /dev/null
+++ b/tests/crashes/137895.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #137895
+trait A {
+    fn b() -> impl ?Sized + 'a;
+}
+
+impl A for dyn A {}
diff --git a/tests/crashes/137916.rs b/tests/crashes/137916.rs
new file mode 100644
index 00000000000..3d6b0e0fbab
--- /dev/null
+++ b/tests/crashes/137916.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #137916
+//@ compile-flags: --edition=2021
+use std::ptr::null;
+
+async fn a() -> Box<dyn Send> {
+    Box::new(async {
+        let non_send = null::<()>();
+        &non_send;
+        async {}.await
+    })
+}
+
+fn main() {}
diff --git a/tests/crashes/138008.rs b/tests/crashes/138008.rs
new file mode 100644
index 00000000000..4645b8c9d56
--- /dev/null
+++ b/tests/crashes/138008.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #138008
+//@compile-flags: --crate-type=lib -Copt-level=0
+#![feature(repr_simd)]
+const C: usize = 16;
+
+#[repr(simd)]
+pub struct Foo([u8; C]);
+pub unsafe fn foo(a: Foo) {}
diff --git a/tests/crashes/138009.rs b/tests/crashes/138009.rs
new file mode 100644
index 00000000000..a1b890823e7
--- /dev/null
+++ b/tests/crashes/138009.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #138009
+#![feature(min_generic_const_args)]
+#[repr(simd)]
+struct T([isize; N]);
+
+static X: T = T();
diff --git a/tests/crashes/138048.rs b/tests/crashes/138048.rs
new file mode 100644
index 00000000000..fd59f46c752
--- /dev/null
+++ b/tests/crashes/138048.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #138048
+struct Foo;
+
+impl<'b> Foo {
+    fn bar<const V: u8>() {
+        let V;
+    }
+}
diff --git a/tests/crashes/138088.rs b/tests/crashes/138088.rs
new file mode 100644
index 00000000000..25496d804fe
--- /dev/null
+++ b/tests/crashes/138088.rs
@@ -0,0 +1,5 @@
+//@ known-bug: #138088
+#![feature(min_generic_const_args)]
+trait Bar {
+    fn x(&self) -> [i32; Bar::x];
+}
diff --git a/tests/crashes/138089.rs b/tests/crashes/138089.rs
new file mode 100644
index 00000000000..acf27072bdd
--- /dev/null
+++ b/tests/crashes/138089.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #138089
+#![feature(generic_const_exprs)]
+#![feature(min_generic_const_args)]
+#![feature(inherent_associated_types)]
+struct OnDiskDirEntry<'a> {}
+
+impl<'a> OnDiskDirEntry<'a> {
+    const LFN_FRAGMENT_LEN: i64 = 2;
+
+    fn lfn_contents() -> [char; Self::LFN_FRAGMENT_LEN] {
+        loop {}
+    }
+}
diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs
new file mode 100644
index 00000000000..f400c02de8d
--- /dev/null
+++ b/tests/crashes/138131.rs
@@ -0,0 +1,12 @@
+//@ known-bug: #138131
+#![feature(min_generic_const_args)]
+#![feature(inherent_associated_types)]
+struct Foo<'a> {
+    x: &'a (),
+}
+
+impl<'a> Foo<'a> {
+    fn foo(_: [u8; Foo::X]) {}
+}
+
+fn main() {}
diff --git a/tests/crashes/138132.rs b/tests/crashes/138132.rs
new file mode 100644
index 00000000000..3e31117c526
--- /dev/null
+++ b/tests/crashes/138132.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #138132
+#![feature(min_generic_const_args)]
+struct b(Box<[u8; c]>);
+impl b {
+    fn d(self) {
+        self.0.e()
+    }
+}
+struct c<'a>(&'a u8);
+fn main() {}
diff --git a/tests/crashes/138166.rs b/tests/crashes/138166.rs
new file mode 100644
index 00000000000..98003bd6dae
--- /dev/null
+++ b/tests/crashes/138166.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #138166
+#![feature(min_generic_const_args)]
+#![feature(inherent_associated_types)]
+struct a(Box<[u8; Box::b]>);
+impl a {
+  fn c(self) { self.0.d() }
+}
+fn main() {}
diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir
new file mode 100644
index 00000000000..49314a64c3f
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir
@@ -0,0 +1,89 @@
+// MIR for `demo_le` after PreCodegen
+
+fn demo_le(_1: &MultiField, _2: &MultiField) -> bool {
+    debug a => _1;
+    debug b => _2;
+    let mut _0: bool;
+    scope 1 (inlined <MultiField as PartialOrd>::le) {
+        let mut _11: std::option::Option<std::cmp::Ordering>;
+        scope 2 (inlined Option::<std::cmp::Ordering>::is_some_and::<fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le}>) {
+            let _12: std::cmp::Ordering;
+            scope 3 {
+                scope 4 (inlined <fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le} as FnOnce<(std::cmp::Ordering,)>>::call_once - shim(fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le})) {
+                    scope 5 (inlined std::cmp::Ordering::is_le) {
+                        let mut _13: i8;
+                        scope 6 (inlined std::cmp::Ordering::as_raw) {
+                        }
+                    }
+                }
+            }
+        }
+        scope 7 (inlined <MultiField as PartialOrd>::partial_cmp) {
+            let mut _6: std::option::Option<std::cmp::Ordering>;
+            let mut _7: i8;
+            scope 8 {
+            }
+            scope 9 (inlined std::cmp::impls::<impl PartialOrd for char>::partial_cmp) {
+                let mut _3: char;
+                let mut _4: char;
+                let mut _5: std::cmp::Ordering;
+            }
+            scope 10 (inlined std::cmp::impls::<impl PartialOrd for i16>::partial_cmp) {
+                let mut _8: i16;
+                let mut _9: i16;
+                let mut _10: std::cmp::Ordering;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_12);
+        StorageLive(_11);
+        StorageLive(_5);
+        StorageLive(_7);
+        StorageLive(_3);
+        _3 = copy ((*_1).0: char);
+        StorageLive(_4);
+        _4 = copy ((*_2).0: char);
+        _5 = Cmp(move _3, move _4);
+        StorageDead(_4);
+        StorageDead(_3);
+        _6 = Option::<std::cmp::Ordering>::Some(copy _5);
+        _7 = discriminant(_5);
+        switchInt(move _7) -> [0: bb1, otherwise: bb2];
+    }
+
+    bb1: {
+        StorageLive(_10);
+        StorageLive(_8);
+        _8 = copy ((*_1).1: i16);
+        StorageLive(_9);
+        _9 = copy ((*_2).1: i16);
+        _10 = Cmp(move _8, move _9);
+        StorageDead(_9);
+        StorageDead(_8);
+        _11 = Option::<std::cmp::Ordering>::Some(move _10);
+        StorageDead(_10);
+        StorageDead(_7);
+        StorageDead(_5);
+        goto -> bb3;
+    }
+
+    bb2: {
+        _11 = copy _6;
+        StorageDead(_7);
+        StorageDead(_5);
+        goto -> bb3;
+    }
+
+    bb3: {
+        _12 = move ((_11 as Some).0: std::cmp::Ordering);
+        StorageLive(_13);
+        _13 = discriminant(_12);
+        _0 = Le(move _13, const 0_i8);
+        StorageDead(_13);
+        StorageDead(_11);
+        StorageDead(_12);
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs
index bad751edf84..73ae923a6cb 100644
--- a/tests/mir-opt/pre-codegen/derived_ord.rs
+++ b/tests/mir-opt/pre-codegen/derived_ord.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 //@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0
 
 #![crate_type = "lib"]
@@ -6,4 +5,29 @@
 #[derive(PartialOrd, PartialEq)]
 pub struct MultiField(char, i16);
 
+// Because this isn't derived by the impl, it's not on the `{impl#0}-partial_cmp`,
+// and thus we need to call it to see what the inlined generic one produces.
+pub fn demo_le(a: &MultiField, b: &MultiField) -> bool {
+    // CHECK-LABEL: fn demo_le
+    // CHECK: inlined <MultiField as PartialOrd>::le
+    // CHECK: inlined{{.+}}is_some_and
+    // CHECK: inlined <MultiField as PartialOrd>::partial_cmp
+
+    // CHECK: [[A0:_[0-9]+]] = copy ((*_1).0: char);
+    // CHECK: [[B0:_[0-9]+]] = copy ((*_2).0: char);
+    // CHECK: Cmp(move [[A0]], move [[B0]]);
+
+    // CHECK: [[D0:_[0-9]+]] = discriminant({{.+}});
+    // CHECK: switchInt(move [[D0]]) -> [0: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}];
+
+    // CHECK: [[A1:_[0-9]+]] = copy ((*_1).1: i16);
+    // CHECK: [[B1:_[0-9]+]] = copy ((*_2).1: i16);
+    // CHECK: Cmp(move [[A1]], move [[B1]]);
+
+    // CHECK: [[D1:_[0-9]+]] = discriminant({{.+}});
+    // CHECK: _0 = Le(move [[D1]], const 0_i8);
+    *a <= *b
+}
+
 // EMIT_MIR derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
+// EMIT_MIR derived_ord.demo_le.PreCodegen.after.mir
diff --git a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
index 5f4ec1de270..de25eebee77 100644
--- a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
@@ -1,6 +1,6 @@
-// MIR for `<impl at $DIR/derived_ord.rs:6:10: 6:20>::partial_cmp` after PreCodegen
+// MIR for `<impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp` after PreCodegen
 
-fn <impl at $DIR/derived_ord.rs:6:10: 6:20>::partial_cmp(_1: &MultiField, _2: &MultiField) -> Option<std::cmp::Ordering> {
+fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &MultiField) -> Option<std::cmp::Ordering> {
     debug self => _1;
     debug other => _2;
     let mut _0: std::option::Option<std::cmp::Ordering>;
diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs
index 54d13b62f4a..3e54b576fd4 100644
--- a/tests/run-make/broken-pipe-no-ice/rmake.rs
+++ b/tests/run-make/broken-pipe-no-ice/rmake.rs
@@ -11,12 +11,12 @@
 // Internal Compiler Error strangely, but it doesn't even go through normal diagnostic infra. Very
 // strange.
 
-#![feature(anonymous_pipe)]
-
 use std::io::Read;
 use std::process::{Command, Stdio};
 
-use run_make_support::env_var;
+// FIXME(#137532): replace `os_pipe` dependency with std `anonymous_pipe` once that stabilizes and
+// reaches beta.
+use run_make_support::{env_var, os_pipe};
 
 #[derive(Debug, PartialEq)]
 enum Binary {
@@ -25,7 +25,7 @@ enum Binary {
 }
 
 fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) {
-    let (reader, writer) = std::io::pipe().unwrap();
+    let (reader, writer) = os_pipe::pipe().unwrap();
     drop(reader); // close read-end
     cmd.stdout(writer).stderr(Stdio::piped());
 
diff --git a/tests/run-make/cross-lang-lto/rmake.rs b/tests/run-make/cross-lang-lto/rmake.rs
index dc376b561e4..50d37460d8d 100644
--- a/tests/run-make/cross-lang-lto/rmake.rs
+++ b/tests/run-make/cross-lang-lto/rmake.rs
@@ -3,8 +3,6 @@
 // -Clinker-plugin-lto.
 // See https://github.com/rust-lang/rust/pull/50000
 
-#![feature(path_file_prefix)]
-
 use std::path::PathBuf;
 
 use run_make_support::{
@@ -92,10 +90,17 @@ fn check_bitcode(instructions: LibBuild) {
         llvm_ar().extract().arg(&instructions.output).run();
     }
 
-    for object in shallow_find_files(cwd(), |path| {
-        has_prefix(path, instructions.output.file_prefix().unwrap().to_str().unwrap())
+    let objects = shallow_find_files(cwd(), |path| {
+        let mut output_path = instructions.output.clone();
+        output_path.set_extension("");
+        has_prefix(path, output_path.file_name().unwrap().to_str().unwrap())
             && has_extension(path, "o")
-    }) {
+    });
+    assert!(!objects.is_empty());
+    println!("objects: {:#?}", objects);
+
+    for object in objects {
+        println!("reading bitcode: {}", object.display());
         // All generated object files should be LLVM bitcode files - this will fail otherwise.
         llvm_bcanalyzer().input(object).run();
     }
diff --git a/tests/run-make/doctests-merge/rmake.rs b/tests/run-make/doctests-merge/rmake.rs
index a25da7403e2..a88b050c50f 100644
--- a/tests/run-make/doctests-merge/rmake.rs
+++ b/tests/run-make/doctests-merge/rmake.rs
@@ -8,7 +8,6 @@ fn test_and_compare(input_file: &str, stdout_file: &str, edition: &str, dep: &Pa
     let output = cmd
         .input(input_file)
         .arg("--test")
-        .arg("-Zunstable-options")
         .edition(edition)
         .arg("--test-args=--test-threads=1")
         .extern_("foo", dep.display().to_string())
diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs
index f210b7c737b..228cfb0864e 100644
--- a/tests/run-make/issue-107495-archive-permissions/rmake.rs
+++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs
@@ -1,12 +1,9 @@
-#![feature(rustc_private)]
-
-#[cfg(unix)]
-extern crate libc;
-
 #[cfg(unix)]
 use std::os::unix::fs::PermissionsExt;
 use std::path::Path;
 
+#[cfg(unix)]
+use run_make_support::libc;
 use run_make_support::{aux_build, rfs};
 
 fn main() {
diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs
index 15eb186717f..8227c51516f 100644
--- a/tests/run-make/repr128-dwarf/rmake.rs
+++ b/tests/run-make/repr128-dwarf/rmake.rs
@@ -87,14 +87,15 @@ fn main() {
         while let Some((_, entry)) = cursor.next_dfs().unwrap() {
             match entry.tag() {
                 gimli::constants::DW_TAG_variant if !is_old_llvm => {
-                    let value = match entry
-                        .attr(gimli::constants::DW_AT_discr_value)
-                        .unwrap()
-                        .unwrap()
-                        .value()
-                    {
+                    let Some(value) = entry.attr(gimli::constants::DW_AT_discr_value).unwrap()
+                    else {
+                        // `std` enums might have variants without `DW_AT_discr_value`.
+                        continue;
+                    };
+                    let value = match value.value() {
                         AttributeValue::Block(value) => value.to_slice().unwrap().to_vec(),
-                        value => panic!("unexpected DW_AT_discr_value of {value:?}"),
+                        // `std` has non-repr128 enums which don't use `AttributeValue::Block`.
+                        value => continue,
                     };
                     // The `DW_TAG_member` that is a child of `DW_TAG_variant` will contain the
                     // variant's name.
diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
index 1397548a6fc..2183e28e89a 100644
--- a/tests/run-make/unstable-feature-usage-metrics/rmake.rs
+++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
@@ -58,12 +58,17 @@ fn test_metrics_dump() {
         );
 
         let message = rfs::read_to_string(json_path);
-        let parsed: serde_json::Value =
+        let mut parsed: serde_json::Value =
             serde_json::from_str(&message).expect("metrics should be dumped as json");
+        // remove timestamps
+        assert!(parsed["lib_features"][0]["timestamp"].is_number());
+        assert!(parsed["lang_features"][0]["timestamp"].is_number());
+        parsed["lib_features"][0]["timestamp"] = serde_json::json!(null);
+        parsed["lang_features"][0]["timestamp"] = serde_json::json!(null);
         let expected = serde_json::json!(
             {
-                "lib_features":[{"symbol":"ascii_char"}],
-                "lang_features":[{"symbol":"box_patterns","since":null}]
+                "lib_features":[{"symbol":"ascii_char", "timestamp":null}],
+                "lang_features":[{"symbol":"box_patterns","since":null, "timestamp":null}]
             }
         );
 
diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs
new file mode 100644
index 00000000000..badf124bdde
--- /dev/null
+++ b/tests/rustdoc-json/attrs/export_name_2021.rs
@@ -0,0 +1,6 @@
+//@ edition: 2021
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
+#[export_name = "altered"]
+pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs
new file mode 100644
index 00000000000..c5bb9dcc8f6
--- /dev/null
+++ b/tests/rustdoc-json/attrs/export_name_2024.rs
@@ -0,0 +1,9 @@
+//@ edition: 2024
+#![no_std]
+
+// The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024
+// is still `#[export_name = ..]` without the `unsafe` attribute wrapper.
+
+//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
+#[unsafe(export_name = "altered")]
+pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs
new file mode 100644
index 00000000000..dca73abc76a
--- /dev/null
+++ b/tests/rustdoc-json/attrs/must_use.rs
@@ -0,0 +1,9 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='example')].attrs" '["#[must_use]"]'
+#[must_use]
+pub fn example() -> impl Iterator<Item = i64> {}
+
+//@ is "$.index[*][?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]'
+#[must_use = "does nothing if you do not use it"]
+pub fn explicit_message() -> impl Iterator<Item = i64> {}
diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs
new file mode 100644
index 00000000000..258542086ec
--- /dev/null
+++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs
@@ -0,0 +1,6 @@
+//@ edition: 2021
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]'
+#[no_mangle]
+pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs
new file mode 100644
index 00000000000..4c01082d045
--- /dev/null
+++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs
@@ -0,0 +1,9 @@
+//@ edition: 2024
+#![no_std]
+
+// The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024
+// is still `#[no_mangle]` without the `unsafe` attribute wrapper.
+
+//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]'
+#[unsafe(no_mangle)]
+pub extern "C" fn example() {}
diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs
new file mode 100644
index 00000000000..5d738fc0560
--- /dev/null
+++ b/tests/rustdoc-json/attrs/non_exhaustive.rs
@@ -0,0 +1,19 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]'
+#[non_exhaustive]
+pub enum MyEnum {
+    First,
+}
+
+pub enum NonExhaustiveVariant {
+    //@ is "$.index[*][?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]'
+    #[non_exhaustive]
+    Variant(i64),
+}
+
+//@ is "$.index[*][?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]'
+#[non_exhaustive]
+pub struct MyStruct {
+    pub x: i64,
+}
diff --git a/tests/rustdoc-ui/diagnostic-width.stderr b/tests/rustdoc-ui/diagnostic-width.stderr
index d8c4934a576..94fc2343faf 100644
--- a/tests/rustdoc-ui/diagnostic-width.stderr
+++ b/tests/rustdoc-ui/diagnostic-width.stderr
@@ -8,8 +8,8 @@ LL | ... a http://link.com
 note: the lint level is defined here
   --> $DIR/diagnostic-width.rs:2:9
    |
-LL | ...ny(rustdoc::bare_url...
-   |       ^^^^^^^^^^^^^^^^^^
+LL | ...ny(ru...are_urls)]
+   |       ^^...^^^^^^^^
 help: use an automatic link instead
    |
 LL | /// This is a long line that contains a <http://link.com>
diff --git a/tests/rustdoc-ui/doctest/doctest-output.rs b/tests/rustdoc-ui/doctest/doctest-output.rs
index fb4ab068000..04bd1813b4c 100644
--- a/tests/rustdoc-ui/doctest/doctest-output.rs
+++ b/tests/rustdoc-ui/doctest/doctest-output.rs
@@ -2,7 +2,7 @@
 //@[edition2015]edition:2015
 //@[edition2015]aux-build:extern_macros.rs
 //@[edition2015]compile-flags:--test --test-args=--test-threads=1
-//@[edition2024]edition:2015
+//@[edition2024]edition:2024
 //@[edition2024]aux-build:extern_macros.rs
 //@[edition2024]compile-flags:--test --test-args=--test-threads=1
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout
new file mode 100644
index 00000000000..ce767fb8443
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout
@@ -0,0 +1,28 @@
+
+running 1 test
+test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ----
+error[E0432]: unresolved import `test`
+  --> $DIR/failed-doctest-test-crate.rs:15:5
+   |
+LL | use test::*;
+   |     ^^^^ use of unresolved module or unlinked crate `test`
+   |
+help: you might be missing a crate named `test`, add it to your project and import it in your code
+   |
+LL + extern crate test;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0432`.
+Couldn't compile the test.
+
+failures:
+    $DIR/failed-doctest-test-crate.rs - m (line 14)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout
new file mode 100644
index 00000000000..80642e93bbd
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout
@@ -0,0 +1,25 @@
+
+running 1 test
+test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ----
+error[E0432]: unresolved import `test`
+  --> $DIR/failed-doctest-test-crate.rs:15:5
+   |
+LL | use test::*;
+   |     ^^^^ use of unresolved module or unlinked crate `test`
+   |
+   = help: you might be missing a crate named `test`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0432`.
+Couldn't compile the test.
+
+failures:
+    $DIR/failed-doctest-test-crate.rs - m (line 14)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs
new file mode 100644
index 00000000000..6966d3df11c
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs
@@ -0,0 +1,17 @@
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+//@ revisions: edition2015 edition2024
+//@[edition2015]edition:2015
+//@[edition2024]edition:2024
+//@ compile-flags:--test
+//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ failure-status: 101
+
+/// <https://github.com/rust-lang/rust/pull/137899#discussion_r1976743383>
+///
+/// ```rust
+/// use test::*;
+/// ```
+pub mod m {}
diff --git a/tests/ui-fulldeps/hash-stable-is-unstable.rs b/tests/ui-fulldeps/hash-stable-is-unstable.rs
index dc778695287..a4b8533eb04 100644
--- a/tests/ui-fulldeps/hash-stable-is-unstable.rs
+++ b/tests/ui-fulldeps/hash-stable-is-unstable.rs
@@ -1,4 +1,3 @@
-//@ ignore-stage1 FIXME: this line can be removed once these new error messages are in stage 0 rustc
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 extern crate rustc_data_structures;
 //~^ use of unstable library feature `rustc_private`
diff --git a/tests/ui-fulldeps/hash-stable-is-unstable.stderr b/tests/ui-fulldeps/hash-stable-is-unstable.stderr
index 8d809175875..e7740d744b4 100644
--- a/tests/ui-fulldeps/hash-stable-is-unstable.stderr
+++ b/tests/ui-fulldeps/hash-stable-is-unstable.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
-  --> $DIR/hash-stable-is-unstable.rs:3:1
+  --> $DIR/hash-stable-is-unstable.rs:2:1
    |
 LL | extern crate rustc_data_structures;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | extern crate rustc_data_structures;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
-  --> $DIR/hash-stable-is-unstable.rs:7:1
+  --> $DIR/hash-stable-is-unstable.rs:6:1
    |
 LL | extern crate rustc_macros;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | extern crate rustc_macros;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
-  --> $DIR/hash-stable-is-unstable.rs:11:1
+  --> $DIR/hash-stable-is-unstable.rs:10:1
    |
 LL | extern crate rustc_query_system;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL | extern crate rustc_query_system;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
-  --> $DIR/hash-stable-is-unstable.rs:16:5
+  --> $DIR/hash-stable-is-unstable.rs:15:5
    |
 LL | use rustc_macros::HashStable;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL | use rustc_macros::HashStable;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
-  --> $DIR/hash-stable-is-unstable.rs:21:10
+  --> $DIR/hash-stable-is-unstable.rs:20:10
    |
 LL | #[derive(HashStable)]
    |          ^^^^^^^^^^
diff --git a/tests/ui-fulldeps/pathless-extern-unstable.rs b/tests/ui-fulldeps/pathless-extern-unstable.rs
index 27272135696..b5ba4082e9d 100644
--- a/tests/ui-fulldeps/pathless-extern-unstable.rs
+++ b/tests/ui-fulldeps/pathless-extern-unstable.rs
@@ -1,4 +1,3 @@
-//@ ignore-stage1 FIXME: this line can be removed once these new error messages are in stage 0 rustc
 //@ edition:2018
 //@ compile-flags:--extern rustc_middle
 
diff --git a/tests/ui-fulldeps/pathless-extern-unstable.stderr b/tests/ui-fulldeps/pathless-extern-unstable.stderr
index a78b69f4d20..779c3773a9b 100644
--- a/tests/ui-fulldeps/pathless-extern-unstable.stderr
+++ b/tests/ui-fulldeps/pathless-extern-unstable.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
-  --> $DIR/pathless-extern-unstable.rs:7:9
+  --> $DIR/pathless-extern-unstable.rs:6:9
    |
 LL | pub use rustc_middle;
    |         ^^^^^^^^^^^^
diff --git a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs
new file mode 100644
index 00000000000..b7636d116ec
--- /dev/null
+++ b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs
@@ -0,0 +1,26 @@
+//@ revisions: emit_mir instrument cfi
+
+// Make sure we don't try to emit MIR for it.
+//@[emit_mir] compile-flags: --emit=mir
+
+// Make sure we don't try to instrument it.
+//@[instrument] compile-flags: -Cinstrument-coverage -Zno-profiler-runtime
+//@[instrument] only-linux
+
+// Make sure we don't try to CFI encode it.
+//@[cfi] compile-flags: -Zsanitizer=cfi -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Clink-dead-code=true
+//@[cfi] needs-sanitizer-cfi
+//@[cfi] no-prefer-dynamic
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@[cfi] only-linux
+
+//@ build-pass
+//@ needs-asm-support
+
+use std::arch::global_asm;
+
+fn foo() {}
+
+global_asm!("/* {} */", sym foo);
+
+fn main() {}
diff --git a/tests/ui/asm/global-asm-with-error.rs b/tests/ui/asm/global-asm-with-error.rs
new file mode 100644
index 00000000000..c2253e3cb87
--- /dev/null
+++ b/tests/ui/asm/global-asm-with-error.rs
@@ -0,0 +1,11 @@
+// Ensure that we don't ICE when constructing the fake MIR body for a global
+// asm when the body has errors. See #137470.
+
+//@ needs-asm-support
+
+use std::arch::global_asm;
+
+global_asm!("/* {} */", sym a);
+//~^ ERROR cannot find value `a` in this scope
+
+fn main() {}
diff --git a/tests/ui/asm/global-asm-with-error.stderr b/tests/ui/asm/global-asm-with-error.stderr
new file mode 100644
index 00000000000..3b76bfd1948
--- /dev/null
+++ b/tests/ui/asm/global-asm-with-error.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/global-asm-with-error.rs:8:29
+   |
+LL | global_asm!("/* {} */", sym a);
+   |                             ^ not found in this scope
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/asm/invalid-const-operand.rs b/tests/ui/asm/invalid-const-operand.rs
index a688f5042db..bbf4001752a 100644
--- a/tests/ui/asm/invalid-const-operand.rs
+++ b/tests/ui/asm/invalid-const-operand.rs
@@ -14,7 +14,7 @@ global_asm!("{}", const 0f32);
 global_asm!("{}", const 0 as *mut u8);
 //~^ ERROR invalid type for `const` operand
 
-fn main() {
+fn test1() {
     unsafe {
         // Const operands must be integers and must be constants.
 
@@ -27,7 +27,11 @@ fn main() {
         //~^ ERROR invalid type for `const` operand
         asm!("{}", const &0);
         //~^ ERROR invalid type for `const` operand
+    }
+}
 
+fn test2() {
+    unsafe {
         // Constants must be... constant
 
         let x = 0;
@@ -47,3 +51,5 @@ fn main() {
         //~^ ERROR attempt to use a non-constant value in a constant
     }
 }
+
+fn main() {}
diff --git a/tests/ui/asm/invalid-const-operand.stderr b/tests/ui/asm/invalid-const-operand.stderr
index 1cedabeef28..01aa843c6fb 100644
--- a/tests/ui/asm/invalid-const-operand.stderr
+++ b/tests/ui/asm/invalid-const-operand.stderr
@@ -1,5 +1,5 @@
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/invalid-const-operand.rs:40:26
+  --> $DIR/invalid-const-operand.rs:44:26
    |
 LL |         asm!("{}", const x);
    |                          ^ non-constant value
@@ -11,7 +11,7 @@ LL +         const x: /* Type */ = 0;
    |
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/invalid-const-operand.rs:43:36
+  --> $DIR/invalid-const-operand.rs:47:36
    |
 LL |         asm!("{}", const const_foo(x));
    |                                    ^ non-constant value
@@ -23,7 +23,7 @@ LL +         const x: /* Type */ = 0;
    |
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/invalid-const-operand.rs:46:36
+  --> $DIR/invalid-const-operand.rs:50:36
    |
 LL |         asm!("{}", const const_bar(x));
    |                                    ^ non-constant value
@@ -80,7 +80,7 @@ error: invalid type for `const` operand
 LL |         asm!("{}", const &0);
    |                    ^^^^^^--
    |                          |
-   |                          is a `&{integer}`
+   |                          is a `&i32`
    |
    = help: `const` operands must be of an integer type
 
diff --git a/tests/ui/asm/tainting-on-error.rs b/tests/ui/asm/tainting-on-error.rs
new file mode 100644
index 00000000000..a8e9af91158
--- /dev/null
+++ b/tests/ui/asm/tainting-on-error.rs
@@ -0,0 +1,13 @@
+//@ needs-asm-support
+
+use std::arch::asm;
+
+fn main() {
+    unsafe {
+        asm!(
+            "/* {} */",
+            sym None::<()>,
+            //~^ ERROR invalid `sym` operand
+        );
+    }
+}
diff --git a/tests/ui/asm/tainting-on-error.stderr b/tests/ui/asm/tainting-on-error.stderr
new file mode 100644
index 00000000000..bd706d1f310
--- /dev/null
+++ b/tests/ui/asm/tainting-on-error.stderr
@@ -0,0 +1,10 @@
+error: invalid `sym` operand
+  --> $DIR/tainting-on-error.rs:9:13
+   |
+LL |             sym None::<()>,
+   |             ^^^^^^^^^^^^^^ is an `Option<()>`
+   |
+   = help: `sym` operands must refer to either a function or a static
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/asm/x86_64/type-check-2.rs b/tests/ui/asm/x86_64/type-check-2.rs
index 1650c595fae..c63042298da 100644
--- a/tests/ui/asm/x86_64/type-check-2.rs
+++ b/tests/ui/asm/x86_64/type-check-2.rs
@@ -7,7 +7,7 @@ use std::arch::{asm, global_asm};
 #[repr(simd)]
 struct SimdNonCopy([f32; 4]);
 
-fn main() {
+fn test1() {
     unsafe {
         // Inputs must be initialized
 
@@ -26,7 +26,11 @@ fn main() {
         asm!("{}", in(reg) v[0]);
         asm!("{}", out(reg) v[0]);
         asm!("{}", inout(reg) v[0]);
+    }
+}
 
+fn test2() {
+    unsafe {
         // Register operands must be Copy
 
         asm!("{}", in(xmm_reg) SimdNonCopy([0.0, 0.0, 0.0, 0.0]));
@@ -68,3 +72,5 @@ fn main() {
         asm!("{}", in(reg) u);
     }
 }
+
+fn main() {}
diff --git a/tests/ui/asm/x86_64/type-check-2.stderr b/tests/ui/asm/x86_64/type-check-2.stderr
index 8b1bfa85fa2..d5c5a3ff1f8 100644
--- a/tests/ui/asm/x86_64/type-check-2.stderr
+++ b/tests/ui/asm/x86_64/type-check-2.stderr
@@ -1,13 +1,13 @@
 error: arguments for inline assembly must be copyable
-  --> $DIR/type-check-2.rs:32:32
+  --> $DIR/type-check-2.rs:36:32
    |
 LL |         asm!("{}", in(xmm_reg) SimdNonCopy([0.0, 0.0, 0.0, 0.0]));
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `SimdNonCopy` does not implement the Copy trait
 
-error: cannot use value of type `{closure@$DIR/type-check-2.rs:44:28: 44:36}` for inline assembly
-  --> $DIR/type-check-2.rs:44:28
+error: cannot use value of type `{closure@$DIR/type-check-2.rs:48:28: 48:36}` for inline assembly
+  --> $DIR/type-check-2.rs:48:28
    |
 LL |         asm!("{}", in(reg) |x: i32| x);
    |                            ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL |         asm!("{}", in(reg) |x: i32| x);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `Vec<i32>` for inline assembly
-  --> $DIR/type-check-2.rs:46:28
+  --> $DIR/type-check-2.rs:50:28
    |
 LL |         asm!("{}", in(reg) vec![0]);
    |                            ^^^^^^^
@@ -24,7 +24,7 @@ LL |         asm!("{}", in(reg) vec![0]);
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot use value of type `(i32, i32, i32)` for inline assembly
-  --> $DIR/type-check-2.rs:48:28
+  --> $DIR/type-check-2.rs:52:28
    |
 LL |         asm!("{}", in(reg) (1, 2, 3));
    |                            ^^^^^^^^^
@@ -32,7 +32,7 @@ LL |         asm!("{}", in(reg) (1, 2, 3));
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `[i32; 3]` for inline assembly
-  --> $DIR/type-check-2.rs:50:28
+  --> $DIR/type-check-2.rs:54:28
    |
 LL |         asm!("{}", in(reg) [1, 2, 3]);
    |                            ^^^^^^^^^
@@ -40,7 +40,7 @@ LL |         asm!("{}", in(reg) [1, 2, 3]);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `fn() {main}` for inline assembly
-  --> $DIR/type-check-2.rs:58:31
+  --> $DIR/type-check-2.rs:62:31
    |
 LL |         asm!("{}", inout(reg) f);
    |                               ^
@@ -48,7 +48,7 @@ LL |         asm!("{}", inout(reg) f);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `&mut i32` for inline assembly
-  --> $DIR/type-check-2.rs:61:31
+  --> $DIR/type-check-2.rs:65:31
    |
 LL |         asm!("{}", inout(reg) r);
    |                               ^
diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr
index 4ca6ef89819..aa22a453744 100644
--- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr
+++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr
@@ -3,6 +3,9 @@ error[E0733]: recursion in an async fn requires boxing
    |
 LL |     async fn second(self) {
    |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         self.first().await.second().await;
+   |         --------------------------------- recursive call here
    |
    = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
 
diff --git a/tests/ui/auto-traits/ungated-impl.rs b/tests/ui/auto-traits/ungated-impl.rs
new file mode 100644
index 00000000000..d46b4b01af9
--- /dev/null
+++ b/tests/ui/auto-traits/ungated-impl.rs
@@ -0,0 +1,7 @@
+auto trait MyTrait {}
+//~^ ERROR auto traits are experimental and possibly buggy
+
+impl<T> !MyTrait for *mut T {}
+//~^ ERROR negative trait bounds are not fully implemented
+
+fn main() {}
diff --git a/tests/ui/auto-traits/ungated-impl.stderr b/tests/ui/auto-traits/ungated-impl.stderr
new file mode 100644
index 00000000000..9d10d46a902
--- /dev/null
+++ b/tests/ui/auto-traits/ungated-impl.stderr
@@ -0,0 +1,23 @@
+error[E0658]: auto traits are experimental and possibly buggy
+  --> $DIR/ungated-impl.rs:1:1
+   |
+LL | auto trait MyTrait {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
+   = help: add `#![feature(auto_traits)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: negative trait bounds are not fully implemented; use marker types for now
+  --> $DIR/ungated-impl.rs:4:9
+   |
+LL | impl<T> !MyTrait for *mut T {}
+   |         ^^^^^^^^
+   |
+   = note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information
+   = help: add `#![feature(negative_impls)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs
new file mode 100644
index 00000000000..cfc0a97989d
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs
@@ -0,0 +1,36 @@
+// Combination of `ptr-to-trait-obj-wrap.rs` and `ptr-to-trait-obj-add-auto.rs`.
+//
+// Checks that you *can't* add auto traits to trait object in pointer casts involving wrapping said
+// traits structures.
+
+trait A {}
+
+struct W<T: ?Sized>(T);
+struct X<T: ?Sized>(T);
+
+fn unwrap(a: *const W<dyn A>) -> *const (dyn A + Send) {
+    a as _
+    //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast
+}
+
+fn unwrap_nested(a: *const W<W<dyn A>>) -> *const W<dyn A + Send> {
+    a as _
+    //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast
+}
+
+fn rewrap(a: *const W<dyn A>) -> *const X<dyn A + Send> {
+    a as _
+    //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast
+}
+
+fn rewrap_nested(a: *const W<W<dyn A>>) -> *const W<X<dyn A + Send>> {
+    a as _
+    //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast
+}
+
+fn wrap(a: *const dyn A) -> *const W<dyn A + Send> {
+    a as _
+    //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast
+}
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr
new file mode 100644
index 00000000000..42cdbc34ee8
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr
@@ -0,0 +1,48 @@
+error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
+  --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:12:5
+   |
+LL |     a as _
+   |     ^^^^^^ unsupported cast
+   |
+   = note: this could allow UB elsewhere
+   = help: use `transmute` if you're sure this is sound
+
+error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
+  --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:17:5
+   |
+LL |     a as _
+   |     ^^^^^^ unsupported cast
+   |
+   = note: this could allow UB elsewhere
+   = help: use `transmute` if you're sure this is sound
+
+error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
+  --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:22:5
+   |
+LL |     a as _
+   |     ^^^^^^ unsupported cast
+   |
+   = note: this could allow UB elsewhere
+   = help: use `transmute` if you're sure this is sound
+
+error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
+  --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:27:5
+   |
+LL |     a as _
+   |     ^^^^^^ unsupported cast
+   |
+   = note: this could allow UB elsewhere
+   = help: use `transmute` if you're sure this is sound
+
+error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
+  --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:32:5
+   |
+LL |     a as _
+   |     ^^^^^^ unsupported cast
+   |
+   = note: this could allow UB elsewhere
+   = help: use `transmute` if you're sure this is sound
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0804`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs
new file mode 100644
index 00000000000..ebe7a06a7a1
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs
@@ -0,0 +1,36 @@
+// Combination of `ptr-to-trait-obj-different-args.rs` and `ptr-to-trait-obj-wrap.rs`.
+//
+// Checks that you *can't* change type arguments of trait objects in pointer casts involving
+// wrapping said traits structures.
+
+trait A<T> {}
+
+struct W<T: ?Sized>(T);
+struct X<T: ?Sized>(T);
+
+fn unwrap<F, G>(a: *const W<dyn A<F>>) -> *const dyn A<G> {
+    a as _
+    //~^ error casting `*const W<(dyn A<F> + 'static)>` as `*const dyn A<G>` is invalid
+}
+
+fn unwrap_nested<F, G>(a: *const W<W<dyn A<F>>>) -> *const W<dyn A<G>> {
+    a as _
+    //~^ error casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<dyn A<G>>` is invalid
+}
+
+fn rewrap<F, G>(a: *const W<dyn A<F>>) -> *const X<dyn A<G>> {
+    a as _
+    //~^ error: casting `*const W<(dyn A<F> + 'static)>` as `*const X<dyn A<G>>` is invalid
+}
+
+fn rewrap_nested<F, G>(a: *const W<W<dyn A<F>>>) -> *const W<X<dyn A<G>>> {
+    a as _
+    //~^ error: casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<X<dyn A<G>>>` is invalid
+}
+
+fn wrap<F, G>(a: *const dyn A<F>) -> *const W<dyn A<G>> {
+    a as _
+    //~^ error: casting `*const (dyn A<F> + 'static)` as `*const W<dyn A<G>>` is invalid
+}
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr
new file mode 100644
index 00000000000..4f85b208d05
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr
@@ -0,0 +1,43 @@
+error[E0606]: casting `*const W<(dyn A<F> + 'static)>` as `*const dyn A<G>` is invalid
+  --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:12:5
+   |
+LL |     a as _
+   |     ^^^^^^
+   |
+   = note: the trait objects may have different vtables
+
+error[E0606]: casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<dyn A<G>>` is invalid
+  --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:17:5
+   |
+LL |     a as _
+   |     ^^^^^^
+   |
+   = note: the trait objects may have different vtables
+
+error[E0606]: casting `*const W<(dyn A<F> + 'static)>` as `*const X<dyn A<G>>` is invalid
+  --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:22:5
+   |
+LL |     a as _
+   |     ^^^^^^
+   |
+   = note: the trait objects may have different vtables
+
+error[E0606]: casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<X<dyn A<G>>>` is invalid
+  --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:27:5
+   |
+LL |     a as _
+   |     ^^^^^^
+   |
+   = note: the trait objects may have different vtables
+
+error[E0606]: casting `*const (dyn A<F> + 'static)` as `*const W<dyn A<G>>` is invalid
+  --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:32:5
+   |
+LL |     a as _
+   |     ^^^^^^
+   |
+   = note: the trait objects may have different vtables
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs
new file mode 100644
index 00000000000..b0941277d01
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs
@@ -0,0 +1,41 @@
+// Combination of `ptr-to-trait-obj-different-regions-misc.rs` and `ptr-to-trait-obj-wrap.rs`.
+//
+// Checks that you *can't* change lifetime arguments of trait objects in pointer casts involving
+// wrapping said traits structures.
+
+trait A<'a> {}
+
+struct W<T: ?Sized>(T);
+struct X<T: ?Sized>(T);
+
+fn unwrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const dyn A<'b> {
+    a as _
+    //~^ error
+    //~| error
+}
+
+fn unwrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<dyn A<'b>> {
+    a as _
+    //~^ error
+    //~| error
+}
+
+fn rewrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const X<dyn A<'b>> {
+    a as _
+    //~^ error: lifetime may not live long enough
+    //~| error: lifetime may not live long enough
+}
+
+fn rewrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<X<dyn A<'b>>> {
+    a as _
+    //~^ error: lifetime may not live long enough
+    //~| error: lifetime may not live long enough
+}
+
+fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W<dyn A<'b>> {
+    a as _
+    //~^ error: lifetime may not live long enough
+    //~| error: lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr
new file mode 100644
index 00000000000..17a0ca3c34f
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr
@@ -0,0 +1,140 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:12:5
+   |
+LL | fn unwrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const dyn A<'b> {
+   |           --  -- lifetime `'b` defined here
+   |           |
+   |           lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:12:5
+   |
+LL | fn unwrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const dyn A<'b> {
+   |           --  -- lifetime `'b` defined here
+   |           |
+   |           lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+help: `'b` and `'a` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:18:5
+   |
+LL | fn unwrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<dyn A<'b>> {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:18:5
+   |
+LL | fn unwrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<dyn A<'b>> {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:24:5
+   |
+LL | fn rewrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const X<dyn A<'b>> {
+   |           --  -- lifetime `'b` defined here
+   |           |
+   |           lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:24:5
+   |
+LL | fn rewrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const X<dyn A<'b>> {
+   |           --  -- lifetime `'b` defined here
+   |           |
+   |           lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:30:5
+   |
+LL | fn rewrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<X<dyn A<'b>>> {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:30:5
+   |
+LL | fn rewrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<X<dyn A<'b>>> {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:36:5
+   |
+LL | fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W<dyn A<'b>> {
+   |         --  -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:36:5
+   |
+LL | fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W<dyn A<'b>> {
+   |         --  -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     a as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap.rs b/tests/ui/cast/ptr-to-trait-obj-wrap.rs
new file mode 100644
index 00000000000..6f9f6bddb99
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap.rs
@@ -0,0 +1,33 @@
+// Checks that various casts of pointers to trait objects wrapped in structures
+// work. Note that the metadata doesn't change when a DST is wrapped in a
+// structure, so these casts *are* fine.
+//
+// `unwrap` and `unwrap_nested` currently don't work due to a compiler limitation.
+//@ check-pass
+
+trait A {}
+
+struct W<T: ?Sized>(T);
+struct X<T: ?Sized>(T);
+
+fn unwrap(a: *const W<dyn A>) -> *const dyn A {
+    a as _
+}
+
+fn unwrap_nested(a: *const W<W<dyn A>>) -> *const W<dyn A> {
+    a as _
+}
+
+fn rewrap(a: *const W<dyn A>) -> *const X<dyn A> {
+    a as _
+}
+
+fn rewrap_nested(a: *const W<W<dyn A>>) -> *const W<X<dyn A>> {
+    a as _
+}
+
+fn wrap(a: *const dyn A) -> *const W<dyn A> {
+    a as _
+}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs
index 5eef50e08e2..8260b57bad4 100644
--- a/tests/ui/check-cfg/allow-same-level.rs
+++ b/tests/ui/check-cfg/allow-same-level.rs
@@ -3,7 +3,7 @@
 //
 // It should work, but due to interactions between how #[cfg]s are
 // expanded, the lint machinery and the check-cfg impl, we
-// miss the #[allow], althrough we probably shoudln't.
+// miss the #[allow], althrough we probably shouldn't.
 //
 // cf. https://github.com/rust-lang/rust/issues/124735
 //
diff --git a/tests/ui/codemap_tests/tab_2.stderr b/tests/ui/codemap_tests/tab_2.stderr
index b22c7b42665..4f9a937155d 100644
--- a/tests/ui/codemap_tests/tab_2.stderr
+++ b/tests/ui/codemap_tests/tab_2.stderr
@@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string
 LL |                   """;
    |  ___________________^
 LL | | }
-   | |_^
+   | |__^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs
index e1c6861c510..87c8b04452b 100644
--- a/tests/ui/consts/issue-94675.rs
+++ b/tests/ui/consts/issue-94675.rs
@@ -1,4 +1,4 @@
-#![feature(const_trait_impl, const_vec_string_slice)]
+#![feature(const_trait_impl)]
 
 struct Foo<'a> {
     bar: &'a mut Vec<usize>,
diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr
index 0491bdbc2e1..347f111e79f 100644
--- a/tests/ui/coroutine/gen_block.e2024.stderr
+++ b/tests/ui/coroutine/gen_block.e2024.stderr
@@ -18,16 +18,6 @@ LL |     let _ = #[coroutine] || {};
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: yield syntax is experimental
-  --> $DIR/gen_block.rs:16:16
-   |
-LL |     let _ = || yield true;
-   |                ^^^^^^^^^^
-   |
-   = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
   --> $DIR/gen_block.rs:16:16
    |
@@ -39,23 +29,13 @@ help: use `#[coroutine]` to make this closure a coroutine
 LL |     let _ = #[coroutine] || yield true;
    |             ++++++++++++
 
-error[E0658]: yield syntax is experimental
-  --> $DIR/gen_block.rs:20:29
-   |
-LL |     let _ = #[coroutine] || yield true;
-   |                             ^^^^^^^^^^
-   |
-   = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0282]: type annotations needed
   --> $DIR/gen_block.rs:7:13
    |
 LL |     let x = gen {};
    |             ^^^^^^ cannot infer type
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0282, E0658.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr
index 43437793005..ed744f2957a 100644
--- a/tests/ui/coroutine/gen_block.none.stderr
+++ b/tests/ui/coroutine/gen_block.none.stderr
@@ -71,7 +71,7 @@ LL |     let _ = || yield true;
    |                ^^^^^^^^^^
    |
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
@@ -92,7 +92,7 @@ LL |     let _ = #[coroutine] || yield true;
    |                             ^^^^^^^^^^
    |
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 11 previous errors
diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs
index 4494d654eeb..e3734dd4cdf 100644
--- a/tests/ui/coroutine/gen_block.rs
+++ b/tests/ui/coroutine/gen_block.rs
@@ -14,12 +14,12 @@ fn main() {
     //[none]~^ ERROR: cannot find
 
     let _ = || yield true; //[none]~ ERROR yield syntax is experimental
-    //~^ ERROR yield syntax is experimental
+    //[none]~^ ERROR yield syntax is experimental
     //~^^ ERROR `yield` can only be used in
 
     let _ = #[coroutine] || yield true; //[none]~ ERROR yield syntax is experimental
     //~^ ERROR `#[coroutine]` attribute is an experimental feature
-    //~^^ ERROR yield syntax is experimental
+    //[none]~^^ ERROR yield syntax is experimental
 
     let _ = #[coroutine] || {};
     //~^ ERROR `#[coroutine]` attribute is an experimental feature
diff --git a/tests/ui/delegation/ice-isssue-128190.rs b/tests/ui/delegation/ice-isssue-128190.rs
new file mode 100644
index 00000000000..dab3bbee663
--- /dev/null
+++ b/tests/ui/delegation/ice-isssue-128190.rs
@@ -0,0 +1,9 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+fn a(&self) {}
+//~^ ERROR `self` parameter is only allowed in associated functions
+
+reuse a as b;
+
+fn main() {}
diff --git a/tests/ui/delegation/ice-isssue-128190.stderr b/tests/ui/delegation/ice-isssue-128190.stderr
new file mode 100644
index 00000000000..18f676642c2
--- /dev/null
+++ b/tests/ui/delegation/ice-isssue-128190.stderr
@@ -0,0 +1,10 @@
+error: `self` parameter is only allowed in associated functions
+  --> $DIR/ice-isssue-128190.rs:4:6
+   |
+LL | fn a(&self) {}
+   |      ^^^^^ not semantically valid as function parameter
+   |
+   = note: associated functions are those in `impl` or `trait` definitions
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/diagnostic-width/long-span.long.stderr b/tests/ui/diagnostic-width/long-span.long.stderr
new file mode 100644
index 00000000000..252b17912de
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-span.long.stderr
@@ -0,0 +1,18 @@
+error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
+   ╭▸ $DIR/long-span.rs:7:5056
+   │
+LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0];
+   │       ┬───────────────────────────…────────────────────── ━ ────────────────────────────…────────────────────── [{integer}; 1680]
+   │       │
+   ╰╴      [{integer}; 1680]
+
+error[E0308]: mismatched types
+   ╭▸ $DIR/long-span.rs:9:15
+   │
+LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0];
+   ╰╴      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/diagnostic-width/long-span.longest.stderr b/tests/ui/diagnostic-width/long-span.longest.stderr
new file mode 100644
index 00000000000..2e77c368922
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-span.longest.stderr
@@ -0,0 +1,18 @@
+error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
+  --> $DIR/long-span.rs:7:5056
+   |
+LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+   |       -----------------------------------------...----------------------------------- ^ -----------------------------------------...----------------------------------- [{integer}; 1680]
+   |       |
+   |       [{integer}; 1680]
+
+error[E0308]: mismatched types
+  --> $DIR/long-span.rs:9:15
+   |
+LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/diagnostic-width/long-span.rs b/tests/ui/diagnostic-width/long-span.rs
new file mode 100644
index 00000000000..a3103379e93
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-span.rs
@@ -0,0 +1,11 @@
+//@ revisions: shortest short long longest
+//@[shortest] compile-flags: --diagnostic-width=4
+//@[short] compile-flags: --diagnostic-width=12 -Zunstable-options --json=diagnostic-unicode
+//@[long] compile-flags: --diagnostic-width=80 -Zunstable-options --json=diagnostic-unicode
+//@[longest] compile-flags: --diagnostic-width=120
+// ignore-tidy-linelength
+const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+//~^ ERROR E0369
+const D: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+//~^ ERROR E0308
+fn main() {}
diff --git a/tests/ui/diagnostic-width/long-span.short.stderr b/tests/ui/diagnostic-width/long-span.short.stderr
new file mode 100644
index 00000000000..b4803e31aaa
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-span.short.stderr
@@ -0,0 +1,18 @@
+error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
+   ╭▸ $DIR/long-span.rs:7:5056
+   │
+LL │ …u8 = [0, 0, 0…0] + [0, 0, 0…0];
+   │       ┬───────…── ━ ────────…── [{integer}; 1680]
+   │       │
+   ╰╴      [{integer}; 1680]
+
+error[E0308]: mismatched types
+   ╭▸ $DIR/long-span.rs:9:15
+   │
+LL │ …u8 = [0, 0, 0…0];
+   ╰╴      ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/diagnostic-width/long-span.shortest.stderr b/tests/ui/diagnostic-width/long-span.shortest.stderr
new file mode 100644
index 00000000000..1de1a4acd92
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-span.shortest.stderr
@@ -0,0 +1,18 @@
+error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
+  --> $DIR/long-span.rs:7:5056
+   |
+LL | ... = [0, 0, 0...0] + [0, 0, 0...0];
+   |       --------...-- ^ --------...-- [{integer}; 1680]
+   |       |
+   |       [{integer}; 1680]
+
+error[E0308]: mismatched types
+  --> $DIR/long-span.rs:9:15
+   |
+LL | ... = [0, 0, 0...0];
+   |       ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr
index 4d8afb6f3ad..60ce0d9a148 100644
--- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr
+++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr
@@ -1,11 +1,41 @@
 error[E0369]: cannot add `&str` to `&str`
-  --> $DIR/non-1-width-unicode-multiline-label.rs:7:260
+  --> $DIR/non-1-width-unicode-multiline-label.rs:7:237
    |
-LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
-   |                                                  -------------- ^ -------------- &str
-   |                                                  |              |
-   |                                                  |              `+` cannot be used to concatenate two `&str` strings
-   |                                                  &str
+LL | ...👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
+   |                                                           -------------- ^ -------------- &str
+   |                                                           |              |
+   |                                                           |              `+` cannot be used to concatenate two `&str` strings
+   |                                                           &str
+   |
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
+   |
+LL |     let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
+   |                                                                                                                                                                                                                                                                                                                                                                                                                                                +++++++++++
+
+error[E0369]: cannot add `&str` to `&str`
+  --> $DIR/non-1-width-unicode-multiline-label.rs:9:384
+   |
+LL | ...👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
+   |                                       -------------- ^ -------------- &str
+   |                                       |              |
+   |                                       |              `+` cannot be used to concatenate two `&str` strings
+   |                                       &str
+   |
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
+   |
+LL |     let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
+   |                                                                                                                                                                                                                                                                                                                                                                                                                                                +++++++++++
+
+error[E0369]: cannot add `&str` to `&str`
+  --> $DIR/non-1-width-unicode-multiline-label.rs:11:260
+   |
+LL | ...࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
+   |                                   -------------- ^ -------------- &str
+   |                                   |              |
+   |                                   |              `+` cannot be used to concatenate two `&str` strings
+   |                                   &str
    |
    = note: string concatenation requires an owned `String` on the left
 help: create an owned `String` from a string reference
@@ -13,6 +43,21 @@ help: create an owned `String` from a string reference
 LL |     let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
    |                                                                                                                                                                                         +++++++++++
 
-error: aborting due to 1 previous error
+error[E0369]: cannot add `&str` to `&str`
+  --> $DIR/non-1-width-unicode-multiline-label.rs:13:219
+   |
+LL | ...xxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!";
+   |                                    -------------- ^ -------------- &str
+   |                                    |              |
+   |                                    |              `+` cannot be used to concatenate two `&str` strings
+   |                                    &str
+   |
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
+   |
+LL |     let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!";
+   |                                                                                                                                                                                                                            +++++++++++
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
index e630db8ba42..6b9b27f6297 100644
--- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
+++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
@@ -4,6 +4,12 @@
 
 fn main() {
     let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥";
+    let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
+    //[ascii]~^ ERROR cannot add `&str` to `&str`
+    let _ = "👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦"; let _a = unicode_is_fun + " really fun!";
+    //[ascii]~^ ERROR cannot add `&str` to `&str`
     let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
     //[ascii]~^ ERROR cannot add `&str` to `&str`
+    let _ = "xxxxxxx👨‍👩‍👧‍👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!";
+    //[ascii]~^ ERROR cannot add `&str` to `&str`
 }
diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr
index ed8ce770bb7..15b5dd9d7e2 100644
--- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr
+++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr
@@ -1,11 +1,41 @@
 error[E0369]: cannot add `&str` to `&str`
-   ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260
+   ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:237

-LL │ …ཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉…࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
-   │                                                  ┬───────────── ┯ ────────────── &str
-   │                                                  │              │
-   │                                                  │              `+` cannot be used to concatenate two `&str` strings
-   │                                                  &str
+LL │ …👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
+   │                                                           ┬───────────── ┯ ────────────── &str
+   │                                                           │              │
+   │                                                           │              `+` cannot be used to concatenate two `&str` strings
+   │                                                           &str
+   │
+   ╰ note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
+   ╭╴
+LL │     let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
+   ╰╴                                                                                                                                                                                                                                                                                                                                                                                                                                               +++++++++++
+
+error[E0369]: cannot add `&str` to `&str`
+   ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:9:384
+   │
+LL │ …👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
+   │                                       ┬───────────── ┯ ────────────── &str
+   │                                       │              │
+   │                                       │              `+` cannot be used to concatenate two `&str` strings
+   │                                       &str
+   │
+   ╰ note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
+   ╭╴
+LL │     let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
+   ╰╴                                                                                                                                                                                                                                                                                                                                                                                                                                               +++++++++++
+
+error[E0369]: cannot add `&str` to `&str`
+   ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:11:260
+   │
+LL │ …࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
+   │                                   ┬───────────── ┯ ────────────── &str
+   │                                   │              │
+   │                                   │              `+` cannot be used to concatenate two `&str` strings
+   │                                   &str

    ╰ note: string concatenation requires an owned `String` on the left
 help: create an owned `String` from a string reference
@@ -13,6 +43,21 @@ help: create an owned `String` from a string reference
 LL │     let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
    ╰╴                                                                                                                                                                                        +++++++++++
 
-error: aborting due to 1 previous error
+error[E0369]: cannot add `&str` to `&str`
+   ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:13:219
+   │
+LL │ …xxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!";
+   │                                    ┬───────────── ┯ ────────────── &str
+   │                                    │              │
+   │                                    │              `+` cannot be used to concatenate two `&str` strings
+   │                                    &str
+   │
+   ╰ note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
+   ╭╴
+LL │     let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!";
+   ╰╴                                                                                                                                                                                                                           +++++++++++
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr
index da3d8d31892..5408825d8cd 100644
--- a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr
+++ b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr
@@ -1,10 +1,10 @@
 error[E0308]: mismatched types
   --> $DIR/non-whitespace-trimming-unicode.rs:4:415
    |
-LL | ...♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42;  let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓  ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄...
-   |                                            --   ^^ expected `()`, found integer
-   |                                            |
-   |                                            expected due to this
+LL | ...♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42;  let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓  ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼...
+   |                                                      --   ^^ expected `()`, found integer
+   |                                                      |
+   |                                                      expected due to this
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/diagnostic-width/tabs-trimming.stderr b/tests/ui/diagnostic-width/tabs-trimming.stderr
index 85103fbf6f5..a896345bd70 100644
--- a/tests/ui/diagnostic-width/tabs-trimming.stderr
+++ b/tests/ui/diagnostic-width/tabs-trimming.stderr
@@ -1,20 +1,20 @@
 error[E0408]: variable `v` is not bound in all patterns
   --> $DIR/tabs-trimming.rs:9:16
    |
-LL | ...   v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
-   |       -       ^   ^ pattern doesn't bind `v`
-   |       |       |
-   |       |       pattern doesn't bind `v`
-   |       variable not in all patterns
+LL | ...                     v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
+   |                         -       ^   ^ pattern doesn't bind `v`
+   |                         |       |
+   |                         |       pattern doesn't bind `v`
+   |                         variable not in all patterns
 
 error[E0381]: used binding `v` is possibly-uninitialized
   --> $DIR/tabs-trimming.rs:9:67
    |
-LL | ...   v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
-   |       -                                                          ^ `v` used here but it is possibly-uninitialized
-   |       |
-   |       binding initialized here in some conditions
-   |       binding declared here but left uninitialized
+LL | ...                     v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
+   |                         -                                                          ^ `v` used here but it is possibly-uninitialized
+   |                         |
+   |                         binding initialized here in some conditions
+   |                         binding declared here but left uninitialized
    |
    = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.rs b/tests/ui/dyn-keyword/dyn-2021-edition-error.rs
index 5d607d82ea1..cc23c2c5055 100644
--- a/tests/ui/dyn-keyword/dyn-2021-edition-error.rs
+++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.rs
@@ -7,6 +7,12 @@ fn function(x: &SomeTrait, y: Box<SomeTrait>) {
     //~^ ERROR expected a type, found a trait
 }
 
+// Regression test for <https://github.com/rust-lang/rust/issues/138211>.
+extern "C" {
+    fn foo() -> *const SomeTrait;
+    //~^ ERROR expected a type, found a trait
+}
+
 trait SomeTrait {}
 
 fn main() {}
diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr
index 8c4b809e76b..b1d6385bde9 100644
--- a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr
+++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr
@@ -30,6 +30,17 @@ LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
    |                                   +++
 
 error[E0782]: expected a type, found a trait
+  --> $DIR/dyn-2021-edition-error.rs:12:24
+   |
+LL |     fn foo() -> *const SomeTrait;
+   |                        ^^^^^^^^^
+   |
+help: you can add the `dyn` keyword if you want a trait object
+   |
+LL |     fn foo() -> *const dyn SomeTrait;
+   |                        +++
+
+error[E0782]: expected a type, found a trait
   --> $DIR/dyn-2021-edition-error.rs:6:14
    |
 LL |     let _x: &SomeTrait = todo!();
@@ -40,6 +51,6 @@ help: you can add the `dyn` keyword if you want a trait object
 LL |     let _x: &dyn SomeTrait = todo!();
    |              +++
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0782`.
diff --git a/tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.rs b/tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.rs
new file mode 100644
index 00000000000..4d573b90d60
--- /dev/null
+++ b/tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.rs
@@ -0,0 +1,41 @@
+//@ edition:2021
+trait Trait {}
+
+struct Foo1 {
+    a: Trait,
+    //~^ ERROR expected a type, found a trait
+    b: u32,
+}
+
+struct Foo2 {
+    a: i32,
+    b: Trait,
+    //~^ ERROR expected a type, found a trait
+}
+
+enum Enum1 {
+    A(Trait),
+    //~^ ERROR expected a type, found a trait
+    B(u32),
+}
+
+enum Enum2 {
+    A(u32),
+    B(Trait),
+    //~^ ERROR expected a type, found a trait
+}
+
+// Regression test for <https://github.com/rust-lang/rust/issues/138229>.
+pub struct InWhereClause
+where
+    Trait:, {}
+//~^ ERROR expected a type, found a trait
+
+struct HasGenerics<T> {
+    f: Trait,
+    //~^ ERROR expected a type, found a trait
+    t: T,
+}
+
+
+fn main() {}
diff --git a/tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.stderr b/tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.stderr
new file mode 100644
index 00000000000..9584147bbc7
--- /dev/null
+++ b/tests/ui/dyn-keyword/suggest-struct-or-union-add-generic-impl-trait.stderr
@@ -0,0 +1,74 @@
+error[E0782]: expected a type, found a trait
+  --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:5:8
+   |
+LL |     a: Trait,
+   |        ^^^^^
+   |
+help: you might be missing a type parameter
+   |
+LL ~ struct Foo1<T: Trait> {
+LL ~     a: T,
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:12:8
+   |
+LL |     b: Trait,
+   |        ^^^^^
+   |
+help: you can add the `dyn` keyword if you want a trait object
+   |
+LL |     b: dyn Trait,
+   |        +++
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:17:7
+   |
+LL |     A(Trait),
+   |       ^^^^^
+   |
+help: you might be missing a type parameter
+   |
+LL ~ enum Enum1<T: Trait> {
+LL ~     A(T),
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:24:7
+   |
+LL |     B(Trait),
+   |       ^^^^^
+   |
+help: you might be missing a type parameter
+   |
+LL ~ enum Enum2<T: Trait> {
+LL |     A(u32),
+LL ~     B(T),
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:35:8
+   |
+LL |     f: Trait,
+   |        ^^^^^
+   |
+help: you might be missing a type parameter
+   |
+LL ~ struct HasGenerics<T, U: Trait> {
+LL ~     f: U,
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:31:5
+   |
+LL |     Trait:, {}
+   |     ^^^^^
+   |
+help: you can add the `dyn` keyword if you want a trait object
+   |
+LL |     dyn Trait:, {}
+   |     +++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 905e1249d97..152a6f3a41e 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
@@ -44,22 +44,22 @@ note: while trying to match `r#async`
 LL |     (r#async) => (1)
    |      ^^^^^^^
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `|`, or `||`
    |
   ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8
    |
 LL |     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
    |        -------------------- in this macro invocation
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24
    |
 LL |     if passes_tt!(async) == 1 {}
-   |                        ^ expected one of `move`, `|`, or `||`
+   |                        ^ expected one of `move`, `use`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index af5cc515bb2..53f1b827f9c 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -44,34 +44,34 @@ note: while trying to match `r#async`
 LL |     (r#async) => (1)
    |      ^^^^^^^
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `|`, or `||`
    |
   ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8
    |
 LL |     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
    |        -------------------- in this macro invocation
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24
    |
 LL |     if passes_tt!(async) == 1 {}
-   |                        ^ expected one of `move`, `|`, or `||`
+   |                        ^ expected one of `move`, `use`, `|`, or `||`
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `|`, or `||`
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30
    |
 LL |     if local_passes_tt!(async) == 1 {}
-   |                              ^ expected one of `move`, `|`, or `||`
+   |                              ^ expected one of `move`, `use`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33
diff --git a/tests/ui/ergonomic-clones/async/basic.rs b/tests/ui/ergonomic-clones/async/basic.rs
new file mode 100644
index 00000000000..ad2bfd97cd1
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/basic.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+//@ edition:2018
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+fn ergonomic_clone_async_closures() -> impl Future<Output = String> {
+    let s = String::from("hi");
+
+    async use {
+        s
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/async/edition-2015.rs b/tests/ui/ergonomic-clones/async/edition-2015.rs
new file mode 100644
index 00000000000..d3b2071b9f9
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/edition-2015.rs
@@ -0,0 +1,7 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    async use {};
+    //~^ ERROR `async use` blocks are only allowed in Rust 2018 or later
+}
diff --git a/tests/ui/ergonomic-clones/async/edition-2015.stderr b/tests/ui/ergonomic-clones/async/edition-2015.stderr
new file mode 100644
index 00000000000..b218e6b242e
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/edition-2015.stderr
@@ -0,0 +1,8 @@
+error: `async use` blocks are only allowed in Rust 2018 or later
+  --> $DIR/edition-2015.rs:5:5
+   |
+LL |     async use {};
+   |     ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/ergonomic-clones/async/local-type.rs b/tests/ui/ergonomic-clones/async/local-type.rs
new file mode 100644
index 00000000000..e891686b550
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/local-type.rs
@@ -0,0 +1,10 @@
+// Check that using the parameter name in its type does not ICE.
+//@ edition:2018
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _ = async use |x: x| x; //~ ERROR expected type
+    let _ = async use |x: bool| -> x { x }; //~ ERROR expected type
+}
diff --git a/tests/ui/ergonomic-clones/async/local-type.stderr b/tests/ui/ergonomic-clones/async/local-type.stderr
new file mode 100644
index 00000000000..fd832fbc8d2
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/local-type.stderr
@@ -0,0 +1,15 @@
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:8:27
+   |
+LL |     let _ = async use |x: x| x;
+   |                           ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:9:36
+   |
+LL |     let _ = async use |x: bool| -> x { x };
+   |                                    ^ not a type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/tests/ui/ergonomic-clones/closure/basic.rs b/tests/ui/ergonomic-clones/closure/basic.rs
new file mode 100644
index 00000000000..01d3b08ffa2
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/basic.rs
@@ -0,0 +1,58 @@
+//@ check-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+use std::future::Future;
+
+fn ergonomic_clone_closure_no_captures() -> i32 {
+    let cl = use || {
+        1
+    };
+    cl()
+}
+
+fn ergonomic_clone_closure_move() -> String {
+    let s = String::from("hi");
+
+    let cl = use || {
+        s
+    };
+    cl()
+}
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+fn ergonomic_clone_closure_use_cloned() -> Foo {
+    let f = Foo;
+
+    let f1 = use || {
+        f
+    };
+
+    let f2 = use || {
+        f
+    };
+
+    f
+}
+
+fn ergonomic_clone_closure_copy() -> i32 {
+    let i = 1;
+
+    let i1 = use || {
+        i
+    };
+
+    let i2 = use || {
+        i
+    };
+
+    i
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/const-closure.rs b/tests/ui/ergonomic-clones/closure/const-closure.rs
new file mode 100644
index 00000000000..6b4de824df9
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/const-closure.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+
+#![feature(const_closures)]
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+const fn foo() {
+    let cl = const use || {};
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/expect-region.rs b/tests/ui/ergonomic-clones/closure/expect-region.rs
new file mode 100644
index 00000000000..cbb13e56a18
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/expect-region.rs
@@ -0,0 +1,25 @@
+#![feature(ergonomic_clones)]
+#![allow(warnings)]
+
+fn closure_expecting_bound<F>(_: F)
+where
+    F: FnOnce(&u32),
+{
+}
+
+fn expect_bound_supply_named<'x>() {
+    let mut f: Option<&u32> = None;
+
+    // Here we give a type annotation that `x` should be free. We get
+    // an error because of that.
+    closure_expecting_bound(use |x: &'x u32| {
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR lifetime may not live long enough
+
+        // Borrowck doesn't get a chance to run, but if it did it should error
+        // here.
+        f = Some(x);
+    });
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/expect-region.stderr b/tests/ui/ergonomic-clones/closure/expect-region.stderr
new file mode 100644
index 00000000000..4df1df1378b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/expect-region.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+  --> $DIR/expect-region.rs:15:34
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(use |x: &'x u32| {
+   |                                  ^  - let's call the lifetime of this reference `'1`
+   |                                  |
+   |                                  requires that `'1` must outlive `'x`
+
+error: lifetime may not live long enough
+  --> $DIR/expect-region.rs:15:34
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(use |x: &'x u32| {
+   |                                  ^ requires that `'x` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/ergonomic-clones/closure/fn-once.rs b/tests/ui/ergonomic-clones/closure/fn-once.rs
new file mode 100644
index 00000000000..24060f3ed3b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/fn-once.rs
@@ -0,0 +1,14 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn get_closure() -> Box<dyn Fn() -> Vec<u8>> {
+    let vec = vec![1u8, 2u8];
+
+    let closure = use || { //~ ERROR expected a closure
+        vec
+    };
+
+    Box::new(closure)
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/fn-once.stderr b/tests/ui/ergonomic-clones/closure/fn-once.stderr
new file mode 100644
index 00000000000..40f1200695c
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/fn-once.stderr
@@ -0,0 +1,16 @@
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/fn-once.rs:7:19
+   |
+LL |     let closure = use || {
+   |                   ^^^^^^ this closure implements `FnOnce`, not `Fn`
+LL |         vec
+   |         --- closure is `FnOnce` because it moves the variable `vec` out of its environment
+...
+LL |     Box::new(closure)
+   |     ----------------- the requirement to implement `Fn` derives from here
+   |
+   = note: required for the cast from `Box<{closure@$DIR/fn-once.rs:7:19: 7:25}>` to `Box<(dyn Fn() -> Vec<u8> + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed
new file mode 100644
index 00000000000..1e570632452
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed
@@ -0,0 +1,16 @@
+//@ run-rustfix
+
+// Point at the captured immutable outer variable
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn foo(mut f: Box<dyn FnMut()>) {
+    f();
+}
+
+fn main() {
+    let mut y = true;
+    foo(Box::new(use || y = !y) as Box<_>);
+    //~^ ERROR cannot assign to `y`, as it is not declared as mutable
+}
diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs
new file mode 100644
index 00000000000..59aa61f581d
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs
@@ -0,0 +1,16 @@
+//@ run-rustfix
+
+// Point at the captured immutable outer variable
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn foo(mut f: Box<dyn FnMut()>) {
+    f();
+}
+
+fn main() {
+    let y = true;
+    foo(Box::new(use || y = !y) as Box<_>);
+    //~^ ERROR cannot assign to `y`, as it is not declared as mutable
+}
diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr
new file mode 100644
index 00000000000..f7c742d33fd
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr
@@ -0,0 +1,14 @@
+error[E0594]: cannot assign to `y`, as it is not declared as mutable
+  --> $DIR/immutable-outer-variable.rs:14:25
+   |
+LL |     foo(Box::new(use || y = !y) as Box<_>);
+   |                         ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut y = true;
+   |         +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/ergonomic-clones/closure/local-type.rs b/tests/ui/ergonomic-clones/closure/local-type.rs
new file mode 100644
index 00000000000..b2f99efa1e6
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/local-type.rs
@@ -0,0 +1,9 @@
+// Check that using the parameter name in its type does not ICE.
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _ = use |x: x| x; //~ ERROR expected type
+    let _ = use |x: bool| -> x { x }; //~ ERROR expected type
+}
diff --git a/tests/ui/ergonomic-clones/closure/local-type.stderr b/tests/ui/ergonomic-clones/closure/local-type.stderr
new file mode 100644
index 00000000000..5a42ae63afa
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/local-type.stderr
@@ -0,0 +1,15 @@
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:7:21
+   |
+LL |     let _ = use |x: x| x;
+   |                     ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:8:30
+   |
+LL |     let _ = use |x: bool| -> x { x };
+   |                              ^ not a type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/tests/ui/ergonomic-clones/closure/mutation.rs b/tests/ui/ergonomic-clones/closure/mutation.rs
new file mode 100644
index 00000000000..ef05fffd479
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/mutation.rs
@@ -0,0 +1,12 @@
+//@ check-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let mut my_var = false;
+    let mut callback = use || {
+        my_var = true;
+    };
+    callback();
+}
diff --git a/tests/ui/ergonomic-clones/closure/mutation2.rs b/tests/ui/ergonomic-clones/closure/mutation2.rs
new file mode 100644
index 00000000000..1cb5b8a7ec3
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/mutation2.rs
@@ -0,0 +1,11 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let mut my_var = false;
+    let callback = use || {
+        my_var = true;
+    };
+    callback();
+    //~^ ERROR cannot borrow `callback` as mutable, as it is not declared as mutable [E0596]
+}
diff --git a/tests/ui/ergonomic-clones/closure/mutation2.stderr b/tests/ui/ergonomic-clones/closure/mutation2.stderr
new file mode 100644
index 00000000000..3ff33cf7017
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/mutation2.stderr
@@ -0,0 +1,17 @@
+error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
+  --> $DIR/mutation2.rs:9:5
+   |
+LL |         my_var = true;
+   |         ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
+LL |     };
+LL |     callback();
+   |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = use || {
+   |         +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/ergonomic-clones/closure/nested.rs b/tests/ui/ergonomic-clones/closure/nested.rs
new file mode 100644
index 00000000000..fc364fb594b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/nested.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+fn work(_: Box<Foo>) {}
+fn foo<F:FnOnce()>(_: F) {}
+
+pub fn main() {
+  let a = Box::new(Foo);
+  foo(use || { foo(use || { work(a) }) });
+  let x = use || { use || { Foo } };
+  let _y = x();
+}
diff --git a/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs
new file mode 100644
index 00000000000..a8267ac5359
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs
@@ -0,0 +1,19 @@
+//@ run-pass
+// Testing guarantees provided by once functions.
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::sync::Arc;
+
+fn foo<F: FnOnce()>(blk: F) {
+    blk();
+}
+
+pub fn main() {
+    let x = Arc::new(true);
+    foo(use || {
+        assert!(*x);
+        drop(x);
+    });
+}
diff --git a/tests/ui/ergonomic-clones/closure/parse.rs b/tests/ui/ergonomic-clones/closure/parse.rs
new file mode 100644
index 00000000000..0b3bfae0608
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/parse.rs
@@ -0,0 +1,22 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn parse1() {
+    || use {
+        //~^ ERROR expected one of `async`, `|`, or `||`, found `{`
+    };
+}
+
+fn parse2() {
+    move use || {
+        //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `use`
+    };
+}
+
+fn parse3() {
+    use move || {
+        //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `move`
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/parse.stderr b/tests/ui/ergonomic-clones/closure/parse.stderr
new file mode 100644
index 00000000000..c37cb71394b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/parse.stderr
@@ -0,0 +1,28 @@
+error: expected one of `async`, `|`, or `||`, found `{`
+  --> $DIR/parse.rs:5:12
+   |
+LL |     || use {
+   |     --     ^ expected one of `async`, `|`, or `||`
+   |     |
+   |     while parsing the body of this closure
+   |
+help: you might have meant to open the body of the closure, instead of enclosing the closure in a block
+   |
+LL ~ fn parse1() 
+LL ~     || { use {
+   |
+
+error: expected one of `async`, `|`, or `||`, found keyword `use`
+  --> $DIR/parse.rs:11:10
+   |
+LL |     move use || {
+   |          ^^^ expected one of `async`, `|`, or `||`
+
+error: expected one of `async`, `|`, or `||`, found keyword `move`
+  --> $DIR/parse.rs:17:9
+   |
+LL |     use move || {
+   |         ^^^^ expected one of `async`, `|`, or `||`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.rs b/tests/ui/ergonomic-clones/closure/print-verbose.rs
new file mode 100644
index 00000000000..e80d0d4b649
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print-verbose.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Zverbose-internals
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn to_fn_once<F: FnOnce()>(f: F) -> F {
+    f
+}
+
+fn f<T: std::fmt::Display>(y: T) {
+    struct Foo<U: std::fmt::Display> {
+        x: U,
+    };
+
+    let foo = Foo { x: "x" };
+
+    let c = to_fn_once(use || {
+        println!("{} {}", foo.x, y);
+    });
+
+    c();
+    c();
+    //~^ ERROR use of moved value
+}
+
+fn main() {
+    f("S");
+}
diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.stderr b/tests/ui/ergonomic-clones/closure/print-verbose.stderr
new file mode 100644
index 00000000000..283405c79d6
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print-verbose.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `c`
+  --> $DIR/print-verbose.rs:22:5
+   |
+LL |     let c = to_fn_once(use || {
+   |         - move occurs because `c` has type `{f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'?9 str>, T)}`, which does not implement the `Copy` trait
+...
+LL |     c();
+   |     --- `c` moved due to this call
+LL |     c();
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/print-verbose.rs:21:5
+   |
+LL |     c();
+   |     ^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/ergonomic-clones/closure/print.rs b/tests/ui/ergonomic-clones/closure/print.rs
new file mode 100644
index 00000000000..c24a4cc5094
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print.rs
@@ -0,0 +1,26 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn to_fn_once<F: FnOnce()>(f: F) -> F {
+    f
+}
+
+fn f<T: std::fmt::Display>(y: T) {
+    struct Foo<U: std::fmt::Display> {
+        x: U,
+    };
+
+    let foo = Foo { x: "x" };
+
+    let c = to_fn_once(use || {
+        println!("{} {}", foo.x, y);
+    });
+
+    c();
+    c();
+    //~^ ERROR use of moved value
+}
+
+fn main() {
+    f("S");
+}
diff --git a/tests/ui/ergonomic-clones/closure/print.stderr b/tests/ui/ergonomic-clones/closure/print.stderr
new file mode 100644
index 00000000000..5f48059ebff
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `c`
+  --> $DIR/print.rs:20:5
+   |
+LL |     let c = to_fn_once(use || {
+   |         - move occurs because `c` has type `{closure@$DIR/print.rs:15:24: 15:30}`, which does not implement the `Copy` trait
+...
+LL |     c();
+   |     --- `c` moved due to this call
+LL |     c();
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/print.rs:19:5
+   |
+LL |     c();
+   |     ^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/ergonomic-clones/closure/with-binders.rs b/tests/ui/ergonomic-clones/closure/with-binders.rs
new file mode 100644
index 00000000000..4260c252d9d
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/with-binders.rs
@@ -0,0 +1,10 @@
+//@ edition:2021
+//@ check-pass
+
+#![feature(closure_lifetime_binder)]
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    for<'a> use || -> () {};
+}
diff --git a/tests/ui/ergonomic-clones/dotuse/basic.rs b/tests/ui/ergonomic-clones/dotuse/basic.rs
new file mode 100644
index 00000000000..8f962f079df
--- /dev/null
+++ b/tests/ui/ergonomic-clones/dotuse/basic.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+
+fn basic_test(x: i32) -> i32 {
+    x.use.use.abs()
+}
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+fn do_not_move_test(x: Foo) -> Foo {
+    let s = x.use;
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/dotuse/parse.rs b/tests/ui/ergonomic-clones/dotuse/parse.rs
new file mode 100644
index 00000000000..37ef5c37029
--- /dev/null
+++ b/tests/ui/ergonomic-clones/dotuse/parse.rs
@@ -0,0 +1,39 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn parse1() {
+    1.use!;
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+    }
+
+fn parse2() {
+    1.use!(2);
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+    }
+
+fn parse3() {
+    1.use 2;
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+    }
+
+fn parse4() {
+    1.use? 2;
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+    }
+
+fn parse5() {
+    1.use();
+    //~^ ERROR: incorrect use of `use`
+}
+
+fn parse6() {
+    1.use(2);
+    //~^ ERROR: expected function, found `{integer}` [E0618]
+}
+
+fn parse7() {
+    1.use { 2 };
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/dotuse/parse.stderr b/tests/ui/ergonomic-clones/dotuse/parse.stderr
new file mode 100644
index 00000000000..4b7a92534ed
--- /dev/null
+++ b/tests/ui/ergonomic-clones/dotuse/parse.stderr
@@ -0,0 +1,53 @@
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+  --> $DIR/parse.rs:5:10
+   |
+LL |     1.use!;
+   |          ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+  --> $DIR/parse.rs:10:10
+   |
+LL |     1.use!(2);
+   |          ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+  --> $DIR/parse.rs:15:11
+   |
+LL |     1.use 2;
+   |           ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+  --> $DIR/parse.rs:20:12
+   |
+LL |     1.use? 2;
+   |            ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: incorrect use of `use`
+  --> $DIR/parse.rs:25:10
+   |
+LL |     1.use();
+   |          ^^
+   |
+help: `use` is not a method call, try removing the parentheses
+   |
+LL -     1.use();
+LL +     1.use;
+   |
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
+  --> $DIR/parse.rs:35:11
+   |
+LL |     1.use { 2 };
+   |           ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error[E0618]: expected function, found `{integer}`
+  --> $DIR/parse.rs:30:5
+   |
+LL |     1.use(2);
+   |     ^^^^^---
+   |     |
+   |     call expression requires function
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0618`.
diff --git a/tests/ui/error-codes/E0582.stderr b/tests/ui/error-codes/E0582.stderr
index 64b527cdcc2..ac97a6ff00a 100644
--- a/tests/ui/error-codes/E0582.stderr
+++ b/tests/ui/error-codes/E0582.stderr
@@ -14,7 +14,7 @@ error[E0308]: mismatched types
   --> $DIR/E0582.rs:22:5
    |
 LL |     bar(mk_unexpected_char_err)
-   |     ^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
    = note: expected enum `Option<&_>`
               found enum `Option<&'a _>`
diff --git a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr
index 032d7adf77a..381e7a210be 100644
--- a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr
+++ b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr
@@ -45,7 +45,7 @@ LL |     yield true;
    |     ^^^^^^^^^^
    |
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
@@ -66,7 +66,7 @@ LL |     let _ = || yield true;
    |                ^^^^^^^^^^
    |
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
diff --git a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr
index 032d7adf77a..381e7a210be 100644
--- a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr
+++ b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr
@@ -45,7 +45,7 @@ LL |     yield true;
    |     ^^^^^^^^^^
    |
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
@@ -66,7 +66,7 @@ LL |     let _ = || yield true;
    |                ^^^^^^^^^^
    |
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
-   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs
new file mode 100644
index 00000000000..c2e44064cfa
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs
@@ -0,0 +1,32 @@
+use std::clone::UseCloned;
+//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
+
+fn ergonomic_clone(x: i32) -> i32 {
+    x.use
+    //~^ ERROR ergonomic clones are experimental [E0658]
+}
+
+#[derive(Clone)]
+struct Foo;
+
+fn foo<T: UseCloned>() {}
+//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
+
+impl UseCloned for Foo {}
+//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
+
+fn ergonomic_closure_clone() {
+    let f1 = Foo;
+
+    let f2 = use || {
+        //~^ ERROR ergonomic clones are experimental [E0658]
+        f1
+    };
+
+    let f3 = use || {
+        //~^ ERROR ergonomic clones are experimental [E0658]
+        f1
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr
new file mode 100644
index 00000000000..cf92f2f28df
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr
@@ -0,0 +1,63 @@
+error[E0658]: ergonomic clones are experimental
+  --> $DIR/feature-gate-ergonomic-clones.rs:5:7
+   |
+LL |     x.use
+   |       ^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: ergonomic clones are experimental
+  --> $DIR/feature-gate-ergonomic-clones.rs:21:14
+   |
+LL |     let f2 = use || {
+   |              ^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: ergonomic clones are experimental
+  --> $DIR/feature-gate-ergonomic-clones.rs:26:14
+   |
+LL |     let f3 = use || {
+   |              ^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature `ergonomic_clones`
+  --> $DIR/feature-gate-ergonomic-clones.rs:1:5
+   |
+LL | use std::clone::UseCloned;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature `ergonomic_clones`
+  --> $DIR/feature-gate-ergonomic-clones.rs:12:11
+   |
+LL | fn foo<T: UseCloned>() {}
+   |           ^^^^^^^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature `ergonomic_clones`
+  --> $DIR/feature-gate-ergonomic-clones.rs:15:6
+   |
+LL | impl UseCloned for Foo {}
+   |      ^^^^^^^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-yield-expr.rs b/tests/ui/feature-gates/feature-gate-yield-expr.rs
new file mode 100644
index 00000000000..382bf89069e
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-yield-expr.rs
@@ -0,0 +1,9 @@
+//@ edition: 2024
+#![feature(stmt_expr_attributes)]
+
+fn main() {
+    yield (); //~ ERROR yield syntax is experimental
+    //~^ ERROR yield syntax is experimental
+    //~^^ ERROR `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
+    //~^^^ ERROR yield expression outside of coroutine literal
+}
diff --git a/tests/ui/feature-gates/feature-gate-yield-expr.stderr b/tests/ui/feature-gates/feature-gate-yield-expr.stderr
new file mode 100644
index 00000000000..ad8a15a0f36
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-yield-expr.stderr
@@ -0,0 +1,41 @@
+error[E0658]: yield syntax is experimental
+  --> $DIR/feature-gate-yield-expr.rs:5:5
+   |
+LL |     yield ();
+   |     ^^^^^^^^
+   |
+   = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
+   = help: add `#![feature(coroutines)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: yield syntax is experimental
+  --> $DIR/feature-gate-yield-expr.rs:5:5
+   |
+LL |     yield ();
+   |     ^^^^^^^^
+   |
+   = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
+   = help: add `#![feature(yield_expr)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
+  --> $DIR/feature-gate-yield-expr.rs:5:5
+   |
+LL |     yield ();
+   |     ^^^^^^^^
+   |
+help: use `#[coroutine]` to make this closure a coroutine
+   |
+LL | #[coroutine] fn main() {
+   | ++++++++++++
+
+error[E0627]: yield expression outside of coroutine literal
+  --> $DIR/feature-gate-yield-expr.rs:5:5
+   |
+LL |     yield ();
+   |     ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0627, E0658.
+For more information about an error, try `rustc --explain E0627`.
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr
index 31e11e12835..1c077a9b906 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr
@@ -2,7 +2,7 @@ error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-just-for-static.rs:24:5
    |
 LL |     want_hrtb::<StaticInt>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
    = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
    = note: ...but it actually implements `Foo<&'static isize>`
diff --git a/tests/ui/issues/issue-44078.stderr b/tests/ui/issues/issue-44078.stderr
index 41106b29aad..3e12de34e11 100644
--- a/tests/ui/issues/issue-44078.stderr
+++ b/tests/ui/issues/issue-44078.stderr
@@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string
 LL |       "😊"";
    |  _________^
 LL | | }
-   | |_^
+   | |__^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/layout/post-mono-layout-cycle-2.rs b/tests/ui/layout/post-mono-layout-cycle-2.rs
index 2daac12d7ac..c8a4a222cc6 100644
--- a/tests/ui/layout/post-mono-layout-cycle-2.rs
+++ b/tests/ui/layout/post-mono-layout-cycle-2.rs
@@ -1,4 +1,4 @@
-//@ build-fail
+//@ check-fail
 //@ edition: 2021
 
 use std::future::Future;
diff --git a/tests/ui/layout/post-mono-layout-cycle-2.stderr b/tests/ui/layout/post-mono-layout-cycle-2.stderr
index d8c51deffe3..f04e01071d7 100644
--- a/tests/ui/layout/post-mono-layout-cycle-2.stderr
+++ b/tests/ui/layout/post-mono-layout-cycle-2.stderr
@@ -12,12 +12,6 @@ LL |           Blah::iter(self, iterator).await
    |
    = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
 
-note: the above error was encountered while instantiating `fn Wrap::<()>::ice`
-  --> $DIR/post-mono-layout-cycle-2.rs:54:9
-   |
-LL |         t.ice();
-   |         ^^^^^^^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/lexer/unterminated-nested-comment.stderr b/tests/ui/lexer/unterminated-nested-comment.stderr
index 78b72ce1fe4..9117b689c94 100644
--- a/tests/ui/lexer/unterminated-nested-comment.stderr
+++ b/tests/ui/lexer/unterminated-nested-comment.stderr
@@ -12,7 +12,7 @@ LL | | /*
    | | |
    | | ...as last nested comment starts here, maybe you want to close this instead?
 LL | | */
-   | |_-^
+   | |_--^
    |   |
    |   ...and last nested comment terminates here.
 
diff --git a/tests/ui/lifetimes/static-typos.rs b/tests/ui/lifetimes/static-typos.rs
new file mode 100644
index 00000000000..941d1b376bc
--- /dev/null
+++ b/tests/ui/lifetimes/static-typos.rs
@@ -0,0 +1,7 @@
+fn stati<T: 'stati>() {}
+//~^ ERROR use of undeclared lifetime name `'stati`
+
+fn statoc<T: 'statoc>() {}
+//~^ ERROR use of undeclared lifetime name `'statoc`
+
+fn main() {}
diff --git a/tests/ui/lifetimes/static-typos.stderr b/tests/ui/lifetimes/static-typos.stderr
new file mode 100644
index 00000000000..a817fa89c7e
--- /dev/null
+++ b/tests/ui/lifetimes/static-typos.stderr
@@ -0,0 +1,26 @@
+error[E0261]: use of undeclared lifetime name `'stati`
+  --> $DIR/static-typos.rs:1:13
+   |
+LL | fn stati<T: 'stati>() {}
+   |             ^^^^^^ undeclared lifetime
+   |
+help: you may have misspelled the `'static` lifetime
+   |
+LL | fn stati<T: 'static>() {}
+   |                   +
+
+error[E0261]: use of undeclared lifetime name `'statoc`
+  --> $DIR/static-typos.rs:4:14
+   |
+LL | fn statoc<T: 'statoc>() {}
+   |              ^^^^^^^ undeclared lifetime
+   |
+help: you may have misspelled the `'static` lifetime
+   |
+LL - fn statoc<T: 'statoc>() {}
+LL + fn statoc<T: 'static>() {}
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/linking/no-gc-encapsulation-symbols.rs b/tests/ui/linking/no-gc-encapsulation-symbols.rs
new file mode 100644
index 00000000000..36d69969199
--- /dev/null
+++ b/tests/ui/linking/no-gc-encapsulation-symbols.rs
@@ -0,0 +1,25 @@
+// This test checks that encapsulation symbols are not garbage collected by the linker.
+// LLD will remove them by default, so this test checks that we pass `-znostart-stop-gc` to LLD
+// to avoid that behavior. Without that flag, the test should fail.
+// This test is inspired by the behavior of the linkme crate.
+//
+//@ build-pass
+//@ only-x86_64-unknown-linux-gnu
+
+unsafe extern "Rust" {
+    // The __start_ section name is magical for the linker,
+    // It will put link sections named EXTERNFNS after it.
+    #[link_name = "__start_EXTERNFNS"]
+    static SECTION_START: fn();
+}
+
+#[used]
+#[unsafe(link_section = "EXTERNFNS")]
+static EXTERN_FN_LOCAL: fn() = extern_fn;
+
+fn extern_fn() {}
+
+fn main() {
+    // We need to reference the SECTION_START symbol to avoid it being garbage collected
+    let slice = unsafe { SECTION_START };
+}
diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs
index 20999df9844..db23dcd5e5e 100644
--- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs
+++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs
@@ -1,10 +1,10 @@
 //@ check-pass
 
-// this test checks that the `dead_code` lint is *NOT* being emited
+// this test checks that the `dead_code` lint is *NOT* being emitted
 // for `foo` as `foo` is being used by `main`, and so the `#[expect]`
 // is unfulfilled
 //
-// it also checks that the `dead_code` lint is also *NOT* emited
+// it also checks that the `dead_code` lint is also *NOT* emitted
 // for `bar` as it's suppresed by the `#[expect]` on `bar`
 
 #![warn(dead_code)] // to override compiletest
diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs
index 08103b23387..c4476e43e1f 100644
--- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs
+++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 // this test makes sure that the `unfulfilled_lint_expectations` lint
-// is being emited for `foo` as foo is not dead code, it's pub
+// is being emitted for `foo` as foo is not dead code, it's pub
 
 #![warn(dead_code)] // to override compiletest
 
diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs
index f2625f0781f..ea2e81261d1 100644
--- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs
+++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs
@@ -2,7 +2,7 @@
 //@ revisions: allow expect
 
 // this test checks that no matter if we put #[allow(dead_code)]
-// or #[expect(dead_code)], no warning is being emited
+// or #[expect(dead_code)], no warning is being emitted
 
 #![warn(dead_code)] // to override compiletest
 
diff --git a/tests/ui/lint/lint-incoherent-auto-trait-objects.rs b/tests/ui/lint/lint-incoherent-auto-trait-objects.rs
index d53b5144760..d34e6658435 100644
--- a/tests/ui/lint/lint-incoherent-auto-trait-objects.rs
+++ b/tests/ui/lint/lint-incoherent-auto-trait-objects.rs
@@ -4,16 +4,13 @@ impl Foo for dyn Send {}
 
 impl Foo for dyn Send + Send {}
 //~^ ERROR conflicting implementations
-//~| hard error
 
 impl Foo for dyn Send + Sync {}
 
 impl Foo for dyn Sync + Send {}
 //~^ ERROR conflicting implementations
-//~| hard error
 
 impl Foo for dyn Send + Sync + Send {}
 //~^ ERROR conflicting implementations
-//~| hard error
 
 fn main() {}
diff --git a/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr b/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr
index 553ab3869b3..28e8f74672d 100644
--- a/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr
+++ b/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr
@@ -1,4 +1,4 @@
-error: conflicting implementations of trait `Foo` for type `(dyn Send + 'static)`: (E0119)
+error[E0119]: conflicting implementations of trait `Foo` for type `(dyn Send + 'static)`
   --> $DIR/lint-incoherent-auto-trait-objects.rs:5:1
    |
 LL | impl Foo for dyn Send {}
@@ -6,76 +6,25 @@ LL | impl Foo for dyn Send {}
 LL |
 LL | impl Foo for dyn Send + Send {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-   = note: `#[deny(order_dependent_trait_objects)]` on by default
 
-error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/lint-incoherent-auto-trait-objects.rs:11:1
+error[E0119]: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`
+  --> $DIR/lint-incoherent-auto-trait-objects.rs:10:1
    |
 LL | impl Foo for dyn Send + Sync {}
    | ---------------------------- first implementation here
 LL |
 LL | impl Foo for dyn Sync + Send {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
 
-error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/lint-incoherent-auto-trait-objects.rs:15:1
+error[E0119]: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`
+  --> $DIR/lint-incoherent-auto-trait-objects.rs:13:1
    |
-LL | impl Foo for dyn Sync + Send {}
+LL | impl Foo for dyn Send + Sync {}
    | ---------------------------- first implementation here
 ...
 LL | impl Foo for dyn Send + Sync + Send {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
 
 error: aborting due to 3 previous errors
 
-Future incompatibility report: Future breakage diagnostic:
-error: conflicting implementations of trait `Foo` for type `(dyn Send + 'static)`: (E0119)
-  --> $DIR/lint-incoherent-auto-trait-objects.rs:5:1
-   |
-LL | impl Foo for dyn Send {}
-   | --------------------- first implementation here
-LL |
-LL | impl Foo for dyn Send + Send {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-   = note: `#[deny(order_dependent_trait_objects)]` on by default
-
-Future breakage diagnostic:
-error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/lint-incoherent-auto-trait-objects.rs:11:1
-   |
-LL | impl Foo for dyn Send + Sync {}
-   | ---------------------------- first implementation here
-LL |
-LL | impl Foo for dyn Sync + Send {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-   = note: `#[deny(order_dependent_trait_objects)]` on by default
-
-Future breakage diagnostic:
-error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/lint-incoherent-auto-trait-objects.rs:15:1
-   |
-LL | impl Foo for dyn Sync + Send {}
-   | ---------------------------- first implementation here
-...
-LL | impl Foo for dyn Send + Sync + Send {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-   = note: `#[deny(order_dependent_trait_objects)]` on by default
-
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/lint/unused/must-use-ops.rs b/tests/ui/lint/unused/must-use-ops.rs
index f61cf0fcfcb..5085dbb58c1 100644
--- a/tests/ui/lint/unused/must-use-ops.rs
+++ b/tests/ui/lint/unused/must-use-ops.rs
@@ -6,7 +6,7 @@
 #![feature(never_type)]
 
 fn deref_never(x: &!) {
-    // Don't lint for uninhabited typess
+    // Don't lint for uninhabited types
     *x;
 }
 
diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs b/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs
new file mode 100644
index 00000000000..fc3b51b40a5
--- /dev/null
+++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs
@@ -0,0 +1,20 @@
+//! Test for the crash in #133426, caused by an empty symbol being used for a
+//! type name.
+
+#![allow(incomplete_features)]
+#![feature(never_patterns)]
+
+fn a(
+    _: impl Iterator<
+        Item = [(); {
+            match *todo!() { ! }; //~ ERROR type `!` cannot be dereferenced
+        }],
+    >,
+) {
+}
+
+fn b(_: impl Iterator<Item = { match 0 { ! } }>) {}
+//~^ ERROR associated const equality is incomplete
+//~| ERROR expected type, found constant
+
+fn main() {}
diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr
new file mode 100644
index 00000000000..555d8eec6ba
--- /dev/null
+++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr
@@ -0,0 +1,31 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/no-name-for-DefPath-issue-133426.rs:16:23
+   |
+LL | fn b(_: impl Iterator<Item = { match 0 { ! } }>) {}
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0614]: type `!` cannot be dereferenced
+  --> $DIR/no-name-for-DefPath-issue-133426.rs:10:19
+   |
+LL |             match *todo!() { ! };
+   |                   ^^^^^^^^ can't be dereferenced
+
+error: expected type, found constant
+  --> $DIR/no-name-for-DefPath-issue-133426.rs:16:30
+   |
+LL | fn b(_: impl Iterator<Item = { match 0 { ! } }>) {}
+   |                       ----   ^^^^^^^^^^^^^^^^^ unexpected constant
+   |                       |
+   |                       expected a type because of this associated type
+   |
+note: the associated type is defined here
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0614, E0658.
+For more information about an error, try `rustc --explain E0614`.
diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr
index 17ee8197ac8..be028816e0f 100644
--- a/tests/ui/macros/not-utf8.stderr
+++ b/tests/ui/macros/not-utf8.stderr
@@ -7,7 +7,7 @@ LL |     include!("not-utf8.bin");
 note: byte `193` is not valid utf-8
   --> $DIR/not-utf8.bin:1:1
    |
-LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��-    ��lN~��!@␌ _#���kQ��h�␝�:�...
+LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��-    ��lN~��!@␌ _#���kQ��h�␝�:�␜␇�
    | ^
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/macros/same-sequence-span.stderr b/tests/ui/macros/same-sequence-span.stderr
index ff32ef94386..34df201f5a5 100644
--- a/tests/ui/macros/same-sequence-span.stderr
+++ b/tests/ui/macros/same-sequence-span.stderr
@@ -18,7 +18,7 @@ error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fra
   --> $DIR/same-sequence-span.rs:19:1
    |
 LL | | macro_rules! manual_foo {
-   | |_________________________________^ not allowed after `expr` fragments
+   | |__________________________^not allowed after `expr` fragments
 ...
 LL |   proc_macro_sequence::make_foo!();
    |   ^-------------------------------
diff --git a/tests/ui/nll/issue-97997.rs b/tests/ui/nll/issue-97997.rs
index c64e720b12f..8e0fbe89ac2 100644
--- a/tests/ui/nll/issue-97997.rs
+++ b/tests/ui/nll/issue-97997.rs
@@ -12,5 +12,4 @@ fn main() {
 
     <fn(&u8) as Foo>::ASSOC;
     //~^ ERROR implementation of `Foo` is not general enough
-    //~| ERROR implementation of `Foo` is not general enough
 }
diff --git a/tests/ui/nll/issue-97997.stderr b/tests/ui/nll/issue-97997.stderr
index 89eaf77adf0..ff08daaeaac 100644
--- a/tests/ui/nll/issue-97997.stderr
+++ b/tests/ui/nll/issue-97997.stderr
@@ -7,15 +7,5 @@ LL |     <fn(&u8) as Foo>::ASSOC;
    = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a u8)`
    = note: ...but `Foo` is actually implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
 
-error: implementation of `Foo` is not general enough
-  --> $DIR/issue-97997.rs:13:5
-   |
-LL |     <fn(&u8) as Foo>::ASSOC;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
-   |
-   = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a u8)`
-   = note: ...but `Foo` is actually implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs
index 2fde37ce6ac..b08c830bfc7 100644
--- a/tests/ui/parser/block-no-opening-brace.rs
+++ b/tests/ui/parser/block-no-opening-brace.rs
@@ -30,7 +30,7 @@ fn in_try() {
 // FIXME(#80931)
 fn in_async() {
     async
-        let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let`
+        let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let`
 }
 
 // FIXME(#78168)
diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr
index b65de4eac3f..f51ee92626f 100644
--- a/tests/ui/parser/block-no-opening-brace.stderr
+++ b/tests/ui/parser/block-no-opening-brace.stderr
@@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try`
 LL |     try
    |     ^^^ expected expression
 
-error: expected one of `move`, `|`, or `||`, found keyword `let`
+error: expected one of `move`, `use`, `|`, or `||`, found keyword `let`
   --> $DIR/block-no-opening-brace.rs:33:9
    |
 LL |     async
-   |          - expected one of `move`, `|`, or `||`
+   |          - expected one of `move`, `use`, `|`, or `||`
 LL |         let x = 0;
    |         ^^^ unexpected token
 
diff --git a/tests/ui/parser/byte-string-literals.stderr b/tests/ui/parser/byte-string-literals.stderr
index 08633742557..3e589258d41 100644
--- a/tests/ui/parser/byte-string-literals.stderr
+++ b/tests/ui/parser/byte-string-literals.stderr
@@ -44,7 +44,7 @@ error[E0766]: unterminated double quote byte string
 LL |       b"a
    |  ______^
 LL | | }
-   | |_^
+   | |__^
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr
index a002d54dc91..2507326fb28 100644
--- a/tests/ui/parser/misspelled-keywords/async-move.stderr
+++ b/tests/ui/parser/misspelled-keywords/async-move.stderr
@@ -1,8 +1,8 @@
-error: expected one of `move`, `|`, or `||`, found `Move`
+error: expected one of `move`, `use`, `|`, or `||`, found `Move`
   --> $DIR/async-move.rs:4:11
    |
 LL |     async Move {}
-   |           ^^^^ expected one of `move`, `|`, or `||`
+   |           ^^^^ expected one of `move`, `use`, `|`, or `||`
    |
 help: write keyword `move` in lowercase
    |
diff --git a/tests/ui/parser/raw/too-many-hash.stderr b/tests/ui/parser/raw/too-many-hash.stderr
index 1c46b5385cd..6b3854eb4a2 100644
--- a/tests/ui/parser/raw/too-many-hash.stderr
+++ b/tests/ui/parser/raw/too-many-hash.stderr
@@ -1,8 +1,8 @@
 error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
   --> $DIR/too-many-hash.rs:4:19
    |
-LL | ... = r################################################################################################################################################################################################################################################################"very raw"##############################################################################################################################################################################################################################################################...
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | ... = r####################################################...#######################################;
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/recover/recover-quantified-closure.rs b/tests/ui/parser/recover/recover-quantified-closure.rs
index 10af39b7007..1f5004ad099 100644
--- a/tests/ui/parser/recover/recover-quantified-closure.rs
+++ b/tests/ui/parser/recover/recover-quantified-closure.rs
@@ -7,6 +7,6 @@ fn main() {
 enum Foo { Bar }
 fn foo(x: impl Iterator<Item = Foo>) {
     for <Foo>::Bar in x {}
-    //~^ ERROR expected one of `move`, `static`, `|`
+    //~^ ERROR expected one of `move`, `static`, `use`, `|`
     //~^^ ERROR `for<...>` binders for closures are experimental
 }
diff --git a/tests/ui/parser/recover/recover-quantified-closure.stderr b/tests/ui/parser/recover/recover-quantified-closure.stderr
index 6e03bbb5869..48dea071ae6 100644
--- a/tests/ui/parser/recover/recover-quantified-closure.stderr
+++ b/tests/ui/parser/recover/recover-quantified-closure.stderr
@@ -1,8 +1,8 @@
-error: expected one of `move`, `static`, `|`, or `||`, found `::`
+error: expected one of `move`, `static`, `use`, `|`, or `||`, found `::`
   --> $DIR/recover-quantified-closure.rs:9:14
    |
 LL |     for <Foo>::Bar in x {}
-   |              ^^ expected one of `move`, `static`, `|`, or `||`
+   |              ^^ expected one of `move`, `static`, `use`, `|`, or `||`
 
 error[E0658]: `for<...>` binders for closures are experimental
   --> $DIR/recover-quantified-closure.rs:2:5
diff --git a/tests/ui/parser/unbalanced-doublequote.stderr b/tests/ui/parser/unbalanced-doublequote.stderr
index 9fdad87a86c..d40b982da7c 100644
--- a/tests/ui/parser/unbalanced-doublequote.stderr
+++ b/tests/ui/parser/unbalanced-doublequote.stderr
@@ -3,7 +3,7 @@ error[E0765]: unterminated double quote string
    |
 LL | /     "
 LL | | }
-   | |_^
+   | |__^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr
index d9710c6e6a2..9357a86c415 100644
--- a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr
+++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr
@@ -20,7 +20,7 @@ error: unexpected parameter name
   --> $DIR/patchable-function-entry-attribute.rs:13:46
    |
 LL | #[patchable_function_entry(prefix_nops = 10, something = 0)]
-   |                                              ^^^^^^^^^^^^^ expected prefix_nops or entry_nops
+   |                                              ^^^^^^^^^^^^^ expected `prefix_nops` or `entry_nops`
 
 error: must specify at least one parameter
   --> $DIR/patchable-function-entry-attribute.rs:16:1
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
index d7ade7f0e96..009cc66f3f7 100644
--- a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
+++ b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
@@ -5,7 +5,7 @@
 #![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
+// exist, previous version would fail to compile
 #![crate_type = "rlib"]
 extern crate bar;
 extern crate foo;
diff --git a/tests/ui/repr/repr-empty-packed.rs b/tests/ui/repr/repr-empty-packed.rs
new file mode 100644
index 00000000000..6e390a12b15
--- /dev/null
+++ b/tests/ui/repr/repr-empty-packed.rs
@@ -0,0 +1,9 @@
+//@ compile-flags: --crate-type=lib
+#![deny(unused_attributes)]
+
+#[repr()] //~ ERROR unused attribute
+#[repr(packed)] //~ ERROR attribute should be applied to a struct or union
+pub enum Foo {
+    Bar,
+    Baz(i32),
+}
diff --git a/tests/ui/repr/repr-empty-packed.stderr b/tests/ui/repr/repr-empty-packed.stderr
new file mode 100644
index 00000000000..c824c2998b4
--- /dev/null
+++ b/tests/ui/repr/repr-empty-packed.stderr
@@ -0,0 +1,27 @@
+error: unused attribute
+  --> $DIR/repr-empty-packed.rs:4:1
+   |
+LL | #[repr()]
+   | ^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `repr` with an empty list has no effect
+note: the lint level is defined here
+  --> $DIR/repr-empty-packed.rs:2:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error[E0517]: attribute should be applied to a struct or union
+  --> $DIR/repr-empty-packed.rs:5:8
+   |
+LL |   #[repr(packed)]
+   |          ^^^^^^
+LL | / pub enum Foo {
+LL | |     Bar,
+LL | |     Baz(i32),
+LL | | }
+   | |_- not a struct or union
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0517`.
diff --git a/tests/ui/rust-2024/reserved-guarded-strings.stderr b/tests/ui/rust-2024/reserved-guarded-strings.stderr
index 0f3b06147c4..fde3a719e67 100644
--- a/tests/ui/rust-2024/reserved-guarded-strings.stderr
+++ b/tests/ui/rust-2024/reserved-guarded-strings.stderr
@@ -241,7 +241,7 @@ LL |     demo2!(#"foo"## #);
 error: invalid string literal
   --> $DIR/reserved-guarded-strings.rs:71:12
    |
-LL | ...n!(####################################################################################################################################################################################################################################################################"foo...
+LL | ...n!(####################################################################################################################################################################################################################################################################"foo");
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: unprefixed guarded string literals are reserved for future use since Rust 2024
diff --git a/tests/ui/traits/issue-33140-hack-boundaries.rs b/tests/ui/traits/issue-33140-hack-boundaries.rs
index d091162fced..06786dcc8fe 100644
--- a/tests/ui/traits/issue-33140-hack-boundaries.rs
+++ b/tests/ui/traits/issue-33140-hack-boundaries.rs
@@ -1,5 +1,4 @@
 #![feature(negative_impls)]
-#![allow(order_dependent_trait_objects)]
 
 // Check that the issue #33140 hack does not allow unintended things.
 
@@ -8,6 +7,7 @@ trait Trait0 {}
 
 impl Trait0 for dyn Send {}
 impl Trait0 for dyn Send {}
+//~^ ERROR: E0119
 
 // Problem 1: associated types
 trait Trait1 {
diff --git a/tests/ui/traits/issue-33140-hack-boundaries.stderr b/tests/ui/traits/issue-33140-hack-boundaries.stderr
index d9c4efbb721..ed3ae2b3167 100644
--- a/tests/ui/traits/issue-33140-hack-boundaries.stderr
+++ b/tests/ui/traits/issue-33140-hack-boundaries.stderr
@@ -1,3 +1,11 @@
+error[E0119]: conflicting implementations of trait `Trait0` for type `(dyn Send + 'static)`
+  --> $DIR/issue-33140-hack-boundaries.rs:9:1
+   |
+LL | impl Trait0 for dyn Send {}
+   | ------------------------ first implementation here
+LL | impl Trait0 for dyn Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
+
 error[E0119]: conflicting implementations of trait `Trait1` for type `(dyn Send + 'static)`
   --> $DIR/issue-33140-hack-boundaries.rs:18:1
    |
@@ -62,19 +70,7 @@ LL | impl Trait5 for dyn Send {}
 LL | impl Trait5 for dyn Send where u32: Copy {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0119, E0751.
 For more information about an error, try `rustc --explain E0119`.
-Future incompatibility report: Future breakage diagnostic:
-warning: conflicting implementations of trait `Trait0` for type `(dyn Send + 'static)`: (E0119)
-  --> $DIR/issue-33140-hack-boundaries.rs:10:1
-   |
-LL | impl Trait0 for dyn Send {}
-   | ------------------------ first implementation here
-LL | impl Trait0 for dyn Send {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-
diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.rs b/tests/ui/traits/object/issue-33140-traitobject-crate.rs
index 00ef6430d63..ff7cd30644b 100644
--- a/tests/ui/traits/object/issue-33140-traitobject-crate.rs
+++ b/tests/ui/traits/object/issue-33140-traitobject-crate.rs
@@ -1,6 +1,3 @@
-//@ check-pass
-
-#![warn(order_dependent_trait_objects)]
 #![allow(dyn_drop)]
 
 // Check that traitobject 0.1.0 compiles
@@ -84,15 +81,12 @@ unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Send + Sync { }
 unsafe impl Trait for dyn (::std::marker::Send) + Send { }
 unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
 unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
-//~^ WARNING conflicting implementations of trait `Trait` for type
-//~| WARNING this was previously accepted by the compiler but is being phased out
+//~^ ERROR conflicting implementations of trait `Trait` for type
 unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
-//~^ WARNING conflicting implementations of trait `Trait` for type
-//~| WARNING this was previously accepted by the compiler but is being phased out
+//~^ ERROR conflicting implementations of trait `Trait` for type
 unsafe impl Trait for dyn (::std::marker::Sync) + Sync { }
 unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
-//~^ WARNING conflicting implementations of trait `Trait` for type
-//~| WARNING this was previously accepted by the compiler but is being phased out
+//~^ ERROR conflicting implementations of trait `Trait` for type
 unsafe impl Trait for dyn (::std::ops::Drop) + Send { }
 unsafe impl Trait for dyn (::std::ops::Drop) + Sync { }
 unsafe impl Trait for dyn (::std::ops::Drop) + Send + Sync { }
diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.stderr b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr
index 525401f9d69..a01c7990db3 100644
--- a/tests/ui/traits/object/issue-33140-traitobject-crate.stderr
+++ b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr
@@ -1,95 +1,29 @@
-warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140-traitobject-crate.rs:86:1
+error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`
+  --> $DIR/issue-33140-traitobject-crate.rs:83:1
    |
 LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
    | ------------------------------------------------------ first implementation here
 LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-note: the lint level is defined here
-  --> $DIR/issue-33140-traitobject-crate.rs:3:9
-   |
-LL | #![warn(order_dependent_trait_objects)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140-traitobject-crate.rs:89:1
-   |
-LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
-   | ------------------------------------------------------------- first implementation here
-...
-LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-
-warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140-traitobject-crate.rs:93:1
-   |
-LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
-   | ------------------------------------------------------ first implementation here
-...
-LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-
-warning: 3 warnings emitted
 
-Future incompatibility report: Future breakage diagnostic:
-warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140-traitobject-crate.rs:86:1
+error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`
+  --> $DIR/issue-33140-traitobject-crate.rs:85:1
    |
 LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
    | ------------------------------------------------------ first implementation here
-LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-note: the lint level is defined here
-  --> $DIR/issue-33140-traitobject-crate.rs:3:9
-   |
-LL | #![warn(order_dependent_trait_objects)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140-traitobject-crate.rs:89:1
-   |
-LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
-   | ------------------------------------------------------------- first implementation here
 ...
 LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-note: the lint level is defined here
-  --> $DIR/issue-33140-traitobject-crate.rs:3:9
-   |
-LL | #![warn(order_dependent_trait_objects)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Future breakage diagnostic:
-warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140-traitobject-crate.rs:93:1
+error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`
+  --> $DIR/issue-33140-traitobject-crate.rs:88:1
    |
-LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
    | ------------------------------------------------------ first implementation here
 ...
 LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
-note: the lint level is defined here
-  --> $DIR/issue-33140-traitobject-crate.rs:3:9
-   |
-LL | #![warn(order_dependent_trait_objects)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
index b7c9c131c7d..c9af4bda572 100644
--- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
+++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
@@ -28,7 +28,7 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/implied_lifetime_wf_check3.rs:52:5
    |
 LL |     test_type_param::assert_static::<A>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     the parameter type `A` must be valid for the static lifetime...
    |     ...so that the type `A` will meet its required lifetime bounds
diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
index f23b978d0b6..060d68eb632 100644
--- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
+++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
@@ -21,7 +21,7 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/implied_lifetime_wf_check4_static.rs:17:5
    |
 LL |     assert_static::<A>()
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^
    |     |
    |     the parameter type `A` must be valid for the static lifetime...
    |     ...so that the type `A` will meet its required lifetime bounds
diff --git a/tests/ui/typeck/issue-84768.stderr b/tests/ui/typeck/issue-84768.stderr
index 72784ba59c9..8a2200cbf68 100644
--- a/tests/ui/typeck/issue-84768.stderr
+++ b/tests/ui/typeck/issue-84768.stderr
@@ -20,7 +20,7 @@ help: the return type of this call is `{integer}` due to the type of the argumen
 LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^
    |                                          |
-   |                                          this argument influences the return type of `FnOnce`
+   |                                          this argument influences the return type of `call_once`
 note: method defined here
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
index 05071834883..edee7c4f5a1 100644
--- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
+++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
@@ -25,7 +25,7 @@ help: the return type of this call is `u32` due to the type of the argument pass
 LL |     <i32 as Add<i32>>::add(1u32, 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^----^^^^
    |                            |
-   |                            this argument influences the return type of `Add`
+   |                            this argument influences the return type of `add`
 note: method defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
@@ -48,7 +48,7 @@ help: the return type of this call is `u32` due to the type of the argument pass
 LL |     <i32 as Add<i32>>::add(1, 2u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^----^
    |                               |
-   |                               this argument influences the return type of `Add`
+   |                               this argument influences the return type of `add`
 note: method defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs
index dda362a595e..24a32d8a9ac 100644
--- a/tests/ui/unpretty/deprecated-attr.rs
+++ b/tests/ui/unpretty/deprecated-attr.rs
@@ -1,6 +1,8 @@
 //@ compile-flags: -Zunpretty=hir
 //@ check-pass
 
+// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is
+// slightly broken.
 #[deprecated]
 pub struct PlainDeprecated;
 
diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout
index 60dbac1072b..675351351a0 100644
--- a/tests/ui/unpretty/deprecated-attr.stdout
+++ b/tests/ui/unpretty/deprecated-attr.stdout
@@ -5,17 +5,24 @@ extern crate std;
 //@ compile-flags: -Zunpretty=hir
 //@ check-pass
 
-#[deprecated]
+// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is
+// slightly broken.
+#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
+suggestion: }span: }")]
 struct PlainDeprecated;
 
-#[deprecated = "here's why this is deprecated"]
+#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
+here's why this is deprecatedsuggestion: }span: }")]
 struct DirectNote;
 
-#[deprecated = "here's why this is deprecated"]
+#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
+here's why this is deprecatedsuggestion: }span: }")]
 struct ExplicitNote;
 
-#[deprecated(since = "1.2.3", note = "here's why this is deprecated"]
+#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note:
+here's why this is deprecatedsuggestion: }span: }")]
 struct SinceAndNote;
 
-#[deprecated(since = "1.2.3", note = "here's why this is deprecated"]
+#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note:
+here's why this is deprecatedsuggestion: }span: }")]
 struct FlippedOrder;
diff --git a/triagebot.toml b/triagebot.toml
index ff789e6e362..8db158b95ed 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -18,6 +18,7 @@ allow-unauthenticated = [
     "WG-*",
     "-Z*",
     "beta-nominated",
+    "CI-spurious-*",
     "const-hack",
     "llvm-*",
     "needs-fcp",
@@ -252,7 +253,6 @@ trigger_files = [
     "compiler/rustc_passes/src/check_attr.rs",
     "compiler/rustc_attr_parsing",
     "compiler/rustc_attr_data_structures",
-    "compiler/rustc_attr_validation",
 ]
 
 [autolabel."T-rustdoc-frontend"]
@@ -274,7 +274,7 @@ trigger_files = [
 [autolabel."A-rustdoc-search"]
 trigger_files = [
     "src/librustdoc/html/static/js/search.js",
-    "tests/rustdoc-js",
+    "tests/rustdoc-js/",
     "tests/rustdoc-js-std",
 ]
 
@@ -316,7 +316,6 @@ trigger_files = [
     "library/panic_unwind",
     "library/std",
     "library/stdarch",
-    "library/term",
     "library/test",
 ]
 exclude_labels = [
@@ -331,7 +330,7 @@ trigger_files = [
 [autolabel."O-apple"]
 trigger_files = [
     "library/std/src/os/darwin",
-    "library/std/src/sys/pal/unix/thread_parking/darwin.rs",
+    "library/std/src/sys/sync/thread_parking/darwin.rs",
     "compiler/rustc_target/src/spec/base/apple",
 ]
 
@@ -408,7 +407,8 @@ trigger_files = [
 [autolabel."O-wasm"]
 trigger_files = [
     "library/std/src/sys/pal/wasm",
-    "library/std/src/os/wasm"
+    "library/std/src/os/wasi",
+    "library/std/src/os/wasip2"
 ]
 
 [autolabel."O-windows"]
@@ -499,7 +499,6 @@ trigger_files = [
     "CONTRIBUTING.md",
     "INSTALL.md",
     "REUSE.toml",
-    ".reuse",
     ".mailmap",
     ".git-blame-ignore-revs",
     ".editorconfig"
@@ -524,7 +523,6 @@ exclude_labels = [
 
 [autolabel."WG-trait-system-refactor"]
 trigger_files = [
-    "compiler/rustc_middle/src/traits/solve",
     "compiler/rustc_next_trait_solver",
     "compiler/rustc_trait_selection/src/solve",
     "compiler/rustc_type_ir/src/solve",
@@ -701,6 +699,9 @@ cc = ["@davidtwco", "@wesleywiser"]
 [mentions."compiler/rustc_codegen_cranelift"]
 cc = ["@bjorn3"]
 
+[mentions."compiler/rustc_codegen_ssa"]
+cc = ["@WaffleLapkin"]
+
 [mentions."compiler/rustc_codegen_gcc"]
 cc = ["@antoyo", "@GuillaumeGomez"]
 
@@ -791,7 +792,7 @@ cc = ["@Nadrieril"]
 message = "Some changes occurred in cfg and check-cfg configuration"
 cc = ["@Urgau"]
 
-[mentions."compiler/rustc_lint/src/context/diagnostics/check_cfg.rs"]
+[mentions."compiler/rustc_lint/src/early/diagnostics/check_cfg.rs"]
 message = "Some changes occurred in check-cfg diagnostics"
 cc = ["@Urgau"]
 
@@ -957,7 +958,7 @@ If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/util
 [mentions."src/bootstrap/src/core/build_steps/llvm.rs"]
 message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp."
 
-[mentions."test/crashes"]
+[mentions."tests/crashes"]
 message = "This PR changes a file inside `tests/crashes`. If a crash was fixed, please move into the corresponding `ui` subdir and add 'Fixes #<issueNr>' to the PR description to autoclose the issue upon merge."
 
 [mentions."tests/rustdoc-json"]
@@ -1071,8 +1072,6 @@ cc = ["@jdonszelmann"]
 cc = ["@jdonszelmann"]
 [mentions."compiler/rustc_attr_data_structures"]
 cc = ["@jdonszelmann"]
-[mentions."compiler/rustc_attr_validation"]
-cc = ["@jdonszelmann"]
 
 [assign]
 warn_non_default_branch.enable = true
@@ -1090,6 +1089,10 @@ title = "[stable"
 branch = "stable"
 
 [assign.adhoc_groups]
+compiler_leads = [
+    "@davidtwco",
+    "@wesleywiser",
+]
 compiler = [
     "@BoxyUwU",
     "@cjgillot",
@@ -1257,7 +1260,6 @@ project-exploit-mitigations = [
 "/compiler/rustc_middle/src/traits" =                    ["compiler", "types"]
 "/compiler/rustc_middle/src/ty" =                        ["compiler", "types"]
 "/compiler/rustc_const_eval/src/interpret" =             ["compiler", "mir"]
-"/compiler/rustc_const_eval/src/transform" =             ["compiler", "mir-opt"]
 "/compiler/rustc_mir_build/src/builder" =                ["compiler", "mir"]
 "/compiler/rustc_mir_transform" =                        ["compiler", "mir", "mir-opt"]
 "/compiler/rustc_smir" =                                 ["project-stable-mir"]